source("../Rscripts/BaseScripts.R")
library(cowplot)
library(RColorBrewer)

1 Estiamte SFS with all individuals and all sites

(estimated by each chromosome and combine them later) (5.26.22~)

Step 1: Run PWS07_sfs_step1.sh (in “/Data/Slurumscripts/SFS_fromBam/PWS07_sfs_step1.sh”) for each population (takes a long time to create a saf file)

Step 2: Run PWS07_sfs_step2.sh to create unfolded sfs for each chromosome (Can’t run the whole genome due to memory constraints)

Step 2.2: Run PWS07_sfs_step2_folded.sh to create folded sfs for each chromosome

Step 3: Run R scripts to combine all sfs into 1

# at FARM, run the following scripts to combine sfs files
module load R
R
source("combineSFSfold.R") 
source("combineSFSunfold.R") 
combineSFSunfold("PWS07")   # this will create a "PWS07_unfolded.sfs" in /home/ktist/ph/data/angsd/SFS/fromBam/
combineSFSfold("PWS07")   # this will create a "PWS07_folded.sfs" in /home/ktist/ph/data/angsd/SFS/fromBam/folded/

#Exit R by typing 
quit()

Locally, you can run here:

combineSFSfold<-function(pop){
    ch1<-scan(paste0("Data/new_vcf/angsd/fromBam/folded/",pop,"_folded_chr1.sfs"))
    pws.sfs<-data.frame(chr1=ch1)
    for (i in 2:26){
        vec<-scan(paste0("Data/new_vcf/angsd/fromBam/folded/",pop,"_folded_chr",i,".sfs"))
        pws.sfs[,paste0("chr",i)]<-vec
    }
    pws.sfs$sum<-rowSums(pws.sfs)
    sink(paste0("Data/new_vcf/angsd/fromBam/folded/",pop,"_folded.sfs"))
    cat(pws.sfs$sum)
    sink(NULL)
}

combineSFSunfold<-function(pop){
    ch1<-scan(paste0("Data/new_vcf/angsd/fromBam/unfolded/",pop,"_unfolded_chr1.sfs"))
    pws.sfs<-data.frame(chr1=ch1)
    for (i in 2:26){
        vec<-scan(paste0("Data/new_vcf/angsd/fromBam/unfolded/",pop,"_unfolded_chr",i,".sfs"))
        pws.sfs[,paste0("chr",i)]<-vec
    }
    pws.sfs$sum<-rowSums(pws.sfs)
    sink(paste0("Data/new_vcf/angsd/fromBam/unfolded/",pop,"_unfolded.sfs"))
    cat(pws.sfs$sum)
    sink(NULL)
}

#Run with the 'pop' identifier
combineSFSunfold("PWS07")
combineSFSfold("PWS07")

Step 4: Run PWS07_sfs_theta.sh to calculate theta and Tajima’s D for unfolded.sfs (Fay & Wu’s H should be used with unfolded sfs)

Step 4.2: Run PWS07_sfs_step3_folded.sh to calculate theta and Tajima’s D for folded.sfs (Tajima’s D should be used with folded sfs)

1.1 SFS from bam files

1.1.1 1DSFS PWS

source("../Rscripts/BaseScripts.R")
pops<-c("PWS91","PWS96","PWS07","PWS17")

sfs1D<-data.frame()
for (i in 1:length(pops)){
    sfs <- scan(paste0("../Data/new_vcf/angsd/fromBam/combined/",pops[i],"_unfolded.sfs"))
    sfs1 <- data.frame(ac=sfs)
    sfs1$count<-0:(nrow(sfs1)-1)
    #remove the invariable sites
    sfs1<-sfs1[-c(1,nrow(sfs1)),]
    sfs1$pop<-pops[i]
    sfs1D<-rbind(sfs1D, sfs1)
}
    
sfs1D$pop<-factor(sfs1D$pop, levels=pops)
ggplot(data=sfs1D, aes(x=count, y=ac))+
    facet_wrap(~pop, ncol=4)+
        geom_bar(stat="identity", color="gray")+xlab("Frequency bin")+ ylab("Number of alleles")+
        theme_classic()+
        scale_y_continuous(labels=scales::comma)+
        theme(strip.background = element_rect(
            color="black", fill="gray80", size=0.5, linetype="solid"))
ggsave("../Output/SFS/1DSFS_fromBam_PWS.png", width = 11, height = 2.2, dpi=300)

1.1.2 Pi (π)

pops<-c("PWS91","PWS96","PWS07","PWS17")
theta<-data.frame()
for (i in 1:length(pops)){
    theta2<-read.delim(paste0('../Data/new_vcf/angsd/fromBam/unfolded/',pops[i],'_50kwin_10kstep.pestPG'))
    theta2$pi<-theta2$tP/theta2$nSites
    df<-theta2[,c("Chr","WinCenter","pi","fayh" )]
    df$pop<-pops[i]    
    theta<-rbind(theta, df)
}

#mean pi and Fay's H  (from unfolded SFS)
theta$pop<-factor(theta$pop, levels=pops)

ggplot(theta, aes(x=pop, y=pi))+
    geom_boxplot(position=position_dodge(width = 0.8), color=blu, outlier.alpha = 0.6,outlier.size = 0.7,width=0.6)+
    geom_point(stat = "summary", fun = "mean",position=position_dodge(width = 0.8))+
    ylab(expression(pi))+xlab("")+
    theme_bw()+
    theme(panel.grid.major.x = element_blank())+
    geom_vline(xintercept = c(1.5,2.5,3.5), color="gray", size=0.5)
ggsave("../Output/SFS/Pi_estimates_PWS_fromBam.png", width = 5, height = 3.5)

1.1.3 Fay’s H

ggplot(theta, aes(x=pop, y=fayh))+
    geom_boxplot(position=position_dodge(width = 0.8), color=grb, outlier.alpha = 0.6,outlier.size = 0.7,width=0.6)+
    geom_point(stat = "summary", fun = "mean",position=position_dodge(width = 0.8))+
    ylab("Fay's H")+xlab("")+
    theme_bw()+
    theme(panel.grid.major.x = element_blank())+
    geom_vline(xintercept = c(1.5,2.5,3.5), color="gray", size=0.5)
ggsave("../Output/SFS/FayH_estimates_PWS_fromBam.png", width = 5, height = 3.5)

1.1.4 Tajima’s D

#Tajima's D (folded SFS)
theta<-data.frame()
for (i in 1:length(pops)){
    theta2<-read.delim(paste0('../Data/new_vcf/angsd/fromBam/folded/',pops[i],'_50kwin_10kstep.pestPG'))
    df<-theta2[,c("Chr","WinCenter","Tajima" )]
    df$pop<-pops[i]    
    theta<-rbind(theta, df)
}

theta$pop<-factor(theta$pop, levels=pops)
ggplot(theta, aes(x=pop, y=Tajima))+
    geom_boxplot(position=position_dodge(width = 0.8), color=org, outlier.alpha = 0.6,outlier.size = 0.7,width=0.6)+
    geom_point(stat = "summary", fun = "mean",position=position_dodge(width = 0.8))+
    ylab("Tajima's D")+xlab("")+
    theme_bw()+
    theme(panel.grid.major.x = element_blank())+
    geom_vline(xintercept = c(1.5,2.5,3.5), color="gray", size=0.5)
ggsave("../Output/SFS/TajimaD_PWS_fromBam.png", width = 5, height = 3.5)

1.2 Estimate SFS from VCF files

(Using maf0.00 -no low allele freq cutoff)

Step 1: Run BC17_angsd_SFS.sh (in “/Data/Slurumscripts/SFS_fromVCFmaf00/”) for each population - this will calculate sfs, theta for both folded and unfolded SFS.

Step 2: Create 2D SFS by running each combination (ex. BC17CA172DSFS.sh in “/Data/Slurumscripts/SFS_fromVCFmaf00/”)

Step 3: Calculate Fst/Pbs for population combinations by running 3DFst scripts (ex. 3DFst_pws1.sh)

#Plot 2D SFS (Sfs_comparison.R)
source("../Rscripts/BaseScripts.R")

## 2D SFS
# The output from ANGSD is a flatten matrix: each value is the count of sites with the corresponding joint frequency ordered as
# [0,0] [0,1] [0,2] ..

# function to create a matrix from ANGSD output (a flatten matrix)
vec2mat<-function(vec, n1,n2, pop1, pop2){
    n1<-n1
    n2<-n2
    pop1<-pop1
    pop2<-pop2
    ANGSD.2D.SFS <- scan(paste(vec, sep=""), quiet=T)
    ANGSD.2D.SFS <- t(matrix(ANGSD.2D.SFS, nrow=n2*2+1, ncol=n1*2+1))
    # mask non-variant sites
    ANGSD.2D.SFS[1,1] <- 0
    ANGSD.2D.SFS[nrow(ANGSD.2D.SFS),ncol(ANGSD.2D.SFS)] <- 0
    df<-data.frame(ANGSD.2D.SFS)
    colnames(df)<-0:(ncol(df)-1)
    df$count<-0:(nrow(df)-1)
    return(df)
}

#Plot 2D SFS heatmap     
pops.info<-read.csv("../Data/Sample_metadata_892pops.csv")
pops.info$yr<-''
pops.info$yr[pops.info$year==96|pops.info$year==91]<-paste0(19,pops.info$year[pops.info$year==96|pops.info$year==91])
pops.info$yr[pops.info$year==07|pops.info$year==06|pops.info$year==17]<-paste0(20,pops.info$year[pops.info$year==07|pops.info$year==06|pops.info$year==17])
pops.info$yr<-apply(pops.info["yr"], 1, function(x) {if(x==206) x=2006
                                        if (x==207) x=2007
                                        else x=x})
pops.info$yr<-as.integer(pops.info$yr)
pops<-unique(pops.info$Population.Year)

pwss<-c("PWS91","PWS96","PWS07","PWS17")
tbs<-c("TB91","TB96","TB06","TB17")
sss<-c("SS96","SS06","SS17")
y17<-pops[grep("17",pops)]
comb1<-combn(pwss, 2)
comb1<-t(comb1)
comb2<-combn(tbs, 2)
comb2<-t(comb2)
comb3<-combn(sss, 2)
comb3<-t(comb3)
comb4<-combn(y17, 2)
comb4<-t(comb4)

#https://stackoverflow.com/questions/49689069/heatmap-with-continuous-rainbow-colours
cols <- rev(rainbow(7)[-7]) #rainbow colors for heatmap

#PWS
Plots<-list()
sfs.pws<-data.frame()
for (i in 1: nrow(comb1)){
    pop1<-comb1[i,1]
    pop2<-comb1[i,2]
    n1<-nrow(pops.info[pops.info$Population.Year==pop1,])
    n2<-nrow(pops.info[pops.info$Population.Year==pop2,])
    
    sfs1<-vec2mat(paste0("../Data/new_vcf/angsd/fromVCF/2D/folded_",pop1,"_",pop2,"_maf00.sfs"), n1=n1, n2=n2, pop1=pop1, pop2=pop2)
    
    if (pops.info$yr[pops.info$Population.Year==pop1][1]>pops.info$yr[pops.info$Population.Year==pop2][1]){
        sfs1<-data.frame(t(sfs1[,1:(ncol(sfs1)-1)]))
        colnames(sfs1)<-0:(ncol(sfs1)-1)
        sfs1$count<-0:(nrow(sfs1)-1)
        p2<-pop2
        pop2<-pop1
        pop1<-p2
    }
    #Plot first 30
    sfs2<-sfs1[1:30,1:30]
    sfs2$count<-0:(nrow(sfs2)-1)
    sfsm2<-melt(sfs2, id.vars="count")
    sfsm2$variable<-as.integer(as.character(sfsm2$variable))
    
    #zero as white (replace with NA)
    sfsm2$value[sfsm2$value==0]<-NA
    sfsm2$pop1<-pop1
    sfsm2$pop2<-pop2
    sfs.pws<-rbind(sfs.pws, sfsm2)
}

sfs.pws$pop1<-factor(sfs.pws$pop1, levels=c("PWS91","PWS96","PWS07","PWS17"))
sfs.pws$pop2<-factor(sfs.pws$pop2, levels=c("PWS91","PWS96","PWS07","PWS17"))

ggplot(sfs.pws, aes(x=count, y=variable))+
    facet_grid(pop2~pop1)+
    geom_raster(aes(fill=log10(value)))+xlab('')+ylab("")+
    scale_fill_gradientn(colors=cols, name="log(# of alleles)", na.value = "white")+
    theme_minimal()
ggsave("../Output/SFS/sfs_2D_PWS.png", width = 10, height = 8, dpi=300)
   

#TB
sfs.tb<-data.frame()
for (i in 1: nrow(comb2)){
    pop1<-comb2[i,1]
    pop2<-comb2[i,2]
    n1<-nrow(pops.info[pops.info$Population.Year==pop1,])
    n2<-nrow(pops.info[pops.info$Population.Year==pop2,])
    
    sfs1<-vec2mat(paste0("../Data/new_vcf/angsd/fromVCF/2D/folded_",pop1,"_",pop2,"_maf00.sfs"), n1=n1, n2=n2, pop1=pop1, pop2=pop2)
    
    if (pops.info$yr[pops.info$Population.Year==pop1][1]>pops.info$yr[pops.info$Population.Year==pop2][1]){
        sfs1<-data.frame(t(sfs1[,1:(ncol(sfs1)-1)]))
        colnames(sfs1)<-0:(ncol(sfs1)-1)
        sfs1$count<-0:(nrow(sfs1)-1)
        p2<-pop2
        pop2<-pop1
        pop1<-p2
    }
    #Plot first 30
    sfs2<-sfs1[1:30,1:30]
    sfs2$count<-0:(nrow(sfs2)-1)
    sfsm2<-melt(sfs2, id.vars="count")
    sfsm2$variable<-as.integer(as.character(sfsm2$variable))
    
    #zero as white (replace with NA)
    sfsm2$value[sfsm2$value==0]<-NA
    sfsm2$pop1<-pop1
    sfsm2$pop2<-pop2
    sfs.tb<-rbind(sfs.tb, sfsm2)
}

sfs.tb$pop1<-factor(sfs.tb$pop1, levels=c("TB91","TB96","TB06","TB17"))
sfs.tb$pop2<-factor(sfs.tb$pop2, levels=c("TB91","TB96","TB06","TB17"))

ggplot(sfs.tb, aes(x=count, y=variable))+
    facet_grid(pop2~pop1)+
    geom_raster(aes(fill=log10(value)))+xlab('')+ylab("")+
    scale_fill_gradientn(colors=cols, name="log(# of alleles)", na.value = "white")+
    theme_minimal()
ggsave("../Output/SFS/sfs_2D_TB.png", width = 10, height = 8, dpi=300)

#SS
sfs.ss<-data.frame()
for (i in 1: nrow(comb3)){
    pop1<-comb3[i,1]
    pop2<-comb3[i,2]
    n1<-nrow(pops.info[pops.info$Population.Year==pop1,])
    n2<-nrow(pops.info[pops.info$Population.Year==pop2,])
    sfs1<-vec2mat(paste0("../Data/new_vcf/angsd/fromVCF/2D/folded_",pop1,"_",pop2,"_maf00.sfs"), n1=n1, n2=n2, pop1=pop1, pop2=pop2)
    if (pops.info$yr[pops.info$Population.Year==pop1][1]>pops.info$yr[pops.info$Population.Year==pop2][1]){
        sfs1<-data.frame(t(sfs1[,1:(ncol(sfs1)-1)]))
        colnames(sfs1)<-0:(ncol(sfs1)-1)
        sfs1$count<-0:(nrow(sfs1)-1)
        p2<-pop2
        pop2<-pop1
        pop1<-p2
    }
    #Plot first 30
    sfs2<-sfs1[1:30,1:30]
    sfs2$count<-0:(nrow(sfs2)-1)
    sfsm2<-melt(sfs2, id.vars="count")
    sfsm2$variable<-as.integer(as.character(sfsm2$variable))
    
    #zero as white (replace with NA)
    sfsm2$value[sfsm2$value==0]<-NA
    sfsm2$pop1<-pop1
    sfsm2$pop2<-pop2
    sfs.ss<-rbind(sfs.ss, sfsm2)
}
sfs.ss$pop1<-factor(sfs.ss$pop1, levels=c("SS96","SS06","SS17"))
sfs.ss$pop2<-factor(sfs.ss$pop2, levels=c("SS96","SS06","SS17"))

ggplot(sfs.ss, aes(x=count, y=variable))+
    facet_grid(pop2~pop1)+
    geom_raster(aes(fill=log(value)))+xlab('')+ylab("")+
    scale_fill_gradientn(colors=cols, name="log(# of alleles)", na.value = "white")+
    theme_minimal()
ggsave("../Output/SFS/sfs_2D_SS.png", width = 10, height = 8, dpi=300)

#2017 pops
sfs17<-data.frame()
for (i in 1: nrow(comb4)){
    pop1<-comb4[i,1]
    pop2<-comb4[i,2]
    n1<-nrow(pops.info[pops.info$Population.Year==pop1,])
    n2<-nrow(pops.info[pops.info$Population.Year==pop2,])
    sfs1<-vec2mat(paste0("../Data/new_vcf/angsd/fromVCF/2D/folded_",pop1,"_",pop2,"_maf00.sfs"), n1=n1, n2=n2, pop1=pop1, pop2=pop2)
    
    #Plot first 30
    sfs2<-sfs1[1:30,1:30]
    sfs2$count<-0:(nrow(sfs2)-1)
    sfsm2<-melt(sfs2, id.vars="count")
    sfsm2$variable<-as.integer(as.character(sfsm2$variable))
    
    #zero as white (replace with NA)
    sfsm2$value[sfsm2$value==0]<-NA
    sfsm2$pop1<-pop1
    sfsm2$pop2<-pop2
    sfs17<-rbind(sfs17, sfsm2)
}

sfs17$pop1<-factor(sfs17$pop1, levels=paste(y17))
sfs17$pop2<-factor(sfs17$pop2, levels=paste(y17))

ggplot(sfs17, aes(x=count, y=variable))+
    facet_grid(pop2~pop1)+
    geom_raster(aes(fill=log(value)))+xlab('')+ylab("")+
    scale_fill_gradientn(colors=cols, name="log(# of alleles)", na.value = "white")+
    theme_minimal()
ggsave("../Output/SFS/sfs_2D_2017.png", width = 20, height = 16, dpi=300)

1.2.1 1D SFS all populations (Downsampled bam files)

1.2.2 2D SFS PWS

1.2.3 2D SFS TB

1.2.4 2D SFS SS

1.2.5 2D SFS (2017)

2 Fst between years per population

2.1 PWS

2.1.1 Fst along the genome

### Fst estimates from 2Dsfs
pops<-c("PWS91","PWS96","PWS07","PWS17")
comb<-t(combn(pops,2))

fst<-data.frame()
for (i in 1: nrow(comb)){
    pop1<-comb[i,1]
    pop2<-comb[i,2]
    df<-read.delim(paste0("../Data/new_vcf/angsd/fromVCF/2D/fst_",pop1,"_",pop2,"_50kWindow_maf00"))
    conames<-colnames(df)[2:4]
    colnames(df)[4]<-"Fst"
    colnames(df)[1:3]<-conames
    df$pop<-paste0(pop1,".vs.",pop2)
    df$ch=as.integer(gsub("chr","", df$chr))
    df<-df[order(df$ch),]
    df$loc<-1:nrow(df)
    fst<-rbind(fst, df)
}

evens<-paste0("chr",seq(2,26, by=2))
#Plot Fst valuese across Genome
fst$color<-"col1"
fst$color[fst$chr %in% evens]<-"col2"
fst$pop<-factor(fst$pop, levels=unique(fst$pop))

#add chromosome number
df<-fst[fst$pop=="PWS91.vs.PWS96",]
rows<-data.frame(chr=1:26)
for (i in 1:26){
    if (i ==1){
        rows$n[i]<-nrow(df[df$ch==i,])
        rows$middle[i]<--nrow(df[df$ch==i,])/2
    }
    if (i >1){
        rows$n[i]<-nrow(df[df$ch==i,])
        rows$middle[i]<-sum(rows$n[1:(i-1)])+rows$n[i]/2
    }
}
#
ggplot(fst, aes(x=loc, y=Fst, color=color))+
    facet_wrap(~pop, ncol = 1, strip.position="right")+
    geom_point(size=0.2)+
    scale_color_manual(values=c("gray50","steelblue"))+
    theme_bw()+
    ylab("Fst")+xlab('Genome position')+
    theme(legend.position = "none", panel.grid.major.x = element_blank(), panel.grid.minor.x = element_blank())+
    scale_x_continuous(breaks=rows$middle, labels=1:26)
ggsave("../Output/SFS/PWS_Fst_pairwise_comparison.png", width = 20, height = 10, dpi=150)

Pairwise Fst along the genome
### Pairwise Fst along each chromosome

## Plot Fst values along each chromosome
fst$chr<-factor(fst$chr, levels=paste0("chr",1:26))
fstpw<-fst
plots<-list()
compare<-paste0(unique(fstpw$pop))
max(fstpw$Fst)
for (i in 1:6){ 
    fs<-gsub("vs.","",compare[i])
    pops <- unlist(strsplit(fs, "\\."))
    maxy<-max(fstpw$Fst[fstpw$pop==compare[i]])
    # Fst with actual line to highlight the differences
    plots[[i]] <- ggplot(fstpw[fstpw$pop==compare[i],], aes(x =midPos, y =Fst )) + 
        geom_point(size = 1, color = gry,alpha = 0.4, shape = 1)+
        theme_minimal()+ylim(0,maxy+0.02)+
        theme(axis.text.x=element_blank())+
        ylab("Fst\n")+ xlab("")+ 
        ggtitle(paste0(pops[1]," vs.", pops[2]))+
        geom_line(color=blu, size=0.2)+
        facet_wrap(~chr, ncol = 9)
}
#save the plots together
{png(paste0("../Output/SFS/PWS_Fst_maf00_chr.png"), height = 8, width = 18, res=150, units = "in")
grid.arrange(plots[[3]], plots[[2]], plots[[4]], plots[[1]],plots[[5]],plots[[6]], ncol=3)
dev.off()}

Pairwise Fst for each genome

2.1.2 Create pairwise Fst matrix

## ..continued from above 
pops<-c("PWS91","PWS96","PWS07","PWS17")
comb<-t(combn(pops,2))

## Plot average fst in a heatmap
comp<-unique(fst$pop)
pairfst<-data.frame(matrix(ncol=4, nrow=4), row.names=pops)
colnames(pairfst)<-pops
for (i in 1:6){
    pop1<-comb[i,1]
    pop2<-comb[i,2]
    df<-fst[fst$pop==comp[i],]
    pairfst[pop1,pop2]<-mean(df$Fst, na.rm=T)
    #pairfst[pop2,pop1]<-mean(df$Fst, na.rm=T)
}
write.csv(pairfst,"../Output/SFS/PWS_pairwiseFst_matrix.csv")

pairfst<-read.csv("../Output/SFS/PWS_pairwiseFst_matrix.csv", row.names = 1)
df<-pairfst
diag(df)<-0
df$pop<-rownames(df)
dfm<-melt(df,na.rm=T, id.vars='pop')

#NA to diagonal
dfm$value[dfm$value==0]<-NA
dfm$pop<-factor(dfm$pop, levels=pops)
dfm$value<-round(dfm$value, 4)
ggplot(data = dfm, aes(pop, variable, fill = value))+
    geom_tile(color = "white")+
    scale_fill_gradientn(colors=c("white", "#0C54FF"), limits=c(0, (max(dfm$value, na.rm=T)+0.005)),na.value="gray80", 
                         name="Fst")+
    theme_minimal()+ xlab("")+ylab("")+
    theme(axis.text.x = element_text(angle = 0, vjust = 0, 
                                     size = 12, hjust = 0.5))+
    theme(axis.text.y = element_text(size = 12))+
    coord_fixed()+
    geom_text(aes(pop, variable, label = value), color = "black", size = 5)
ggsave(paste0("../Output/SFS/pairwiseFst_PWS.png"), width = 5, height = 5, dpi=150)

PWS Pairwise Fst

2.1.3 Fst change over time

# Plot Fst in a bar plot ordered and colored in the same way as Fst/Pi shuffle results (Shuffling_pi.fst.tehat.Rmd)
fsts<-dfm[!is.na(dfm$value),]
fsts$comp<-paste0(fsts$pop,"_",fsts$variable)

#set the colors
div1<-diverging_hcl(6, palette="Blue-Red")
div2<-rev(div1)
names(div2)<-c("PWS96_PWS07","PWS07_PWS17","PWS91_PWS96", "PWS91_PWS07", "PWS91_PWS17","PWS96_PWS17")
fsts<-fsts[order(fsts$value, decreasing = T),]
fsts$comp<-factor(fsts$comp, levels=paste0(unique(fsts$comp)))

ggplot(fsts, aes(x=comp, y=value, fill=comp))+
    geom_bar(stat="identity")+
    scale_fill_manual(name = "comp",values = div2)+
    xlab('')+ylab('Fst')+
    theme_classic()+
    theme(axis.text.x = element_text(angle=45, hjust=1), legend.title = element_blank())
ggsave("../Output/Fst/PairwiseFst_ordered.png", width = 4, height = 2.8, dpi=300 )

#Fst over time

fsts2<-fsts[fsts$comp %in% c("PWS91_PWS96","PWS96_PWS07","PWS07_PWS17"),]
fsts2$time<-1
fsts2$time[fsts2$comp=="PWS96_PWS07"]<-2
fsts2$time[fsts2$comp=="PWS07_PWS17"]<-3

ggplot(fsts2, aes(x=time, y=value))+
    geom_point(size=3, color="steelblue")+
    geom_path(color="steelblue")+
    theme_classic()+ylab("Fst")+xlab("")+
    scale_x_continuous(breaks=c(1,2,3), labels=c("91-96", "96-07","07-17"))
ggsave("../Output/Fst/Fst_overTime.png", width = 4, height = 2.8, dpi=300 )

fsts$series<-"1991-2007, 1991-2017"
fsts$series[fsts$comp %in% c("PWS91_PWS96","PWS96_PWS07","PWS07_PWS17")]<-"1991-1996, 1996-2007, 2007-2017"
fsts$series[fsts$comp =="PWS96_PWS17"]<-"1996-2017"
fsts$time<-1
fsts$time[fsts$variable=="PWS17"]<-3
fsts$time[fsts$variable=="PWS07"]<-2
source("../Rscripts/BaseScripts.R")

ggplot(fsts, aes(x=time, y=value, color=series))+
    geom_point(size=3)+
    geom_path()+
    scale_color_manual(values=cols)+
    theme_classic()+ylab("Fst")+xlab("")+
    scale_x_continuous(breaks=c(1,2,3), labels=c("1991-1996", "~2007","~2017"))+
    theme(legend.title = element_blank())
ggsave("../Output/Fst/Fst_overTime_allComparison.png", width = 6, height = 2.8, dpi=300 )


fstP1<-fsts
fstP2<-fsts2

2.1.4 Plot mean Fst for each chromosome

# Plot mean Fst of each chromosme
Fst<-data.frame()
compare<-paste0(unique(fstpw$pop))
for (j in 1:26){
    fst.ch<-fst[fst$ch==j,]
    pairch<-data.frame(matrix(ncol=4, nrow=4), row.names=pops)
    colnames(pairch)<-pops
    for (i in 1:6){
        pop1<-comb[i,1]
        pop2<-comb[i,2]
        df<-fst.ch[fst.ch$pop==compare[i],]
        pairch[pop1,pop2]<-mean(df$Fst, na.rm=T)
    }
    diag(pairch)<-0
    pairch$pop<-rownames(pairch)
    dfm<-melt(pairch,na.rm=T, id.vars='pop')
    
    #NA to diagonal
    dfm$value[dfm$value==0]<-NA
    dfm$pop<-factor(dfm$pop, levels=pops)
    dfm$value<-round(dfm$value, 4)
    dfm$chr<-j
    Fst<-rbind(Fst, dfm)
    
}
Fst$id<-paste0(Fst$pop," vs.",Fst$variable)
Fst<-Fst[!is.na(Fst$value),]
ggplot(Fst, aes(x=chr, y=value,color=id))+
    geom_point()+
    geom_path(stat="identity")+
    theme_minimal()+ylab("Fst")+
    scale_x_continuous(breaks=1:26, labels = 1:26)+
    theme(legend.title = element_blank(), panel.grid.minor.x = element_blank())
ggsave("../Output/SFS/PWS_Fst_byChromosome_dotplot.png", width = 8, height=4.5, dpi=150)

PWS average Fst per chromosome


2.2 Togiak Bay

2.2.1 Pairwise Fst along the genome

2.2.2 Pairwise Fst along each chromosome

#To save the plots, run in R
png(paste0("Output/SFS/TB_Fst_maf00_chr.png"), height = 8, width = 18, res=150, units = "in")  
grid.arrange(plots[[3]], plots[[2]], plots[[4]], plots[[1]],plots[[5]],plots[[6]], ncol=3)  
dev.off()  

2.2.3 Pairwise Fst matrix

## Continued from the above
pops<-c("TB91","TB96","TB06","TB17")
comb<-t(combn(pops,2))

## Plot average fst in a heatmap
compare<-unique(fst$pop)
pairfst<-data.frame(matrix(ncol=4, nrow=4), row.names=pops)
colnames(pairfst)<-pops
for (i in 1:6){
    pop1<-comb[i,1]
    pop2<-comb[i,2]
    df<-fst[fst$pop==compare[i],]
    pairfst[pop1,pop2]<-mean(df$Fst, na.rm=T)
}
write.csv(pairfst,"../Output/SFS/TB_pairwiseFst_matrix.csv")

pairfst<-read.csv("../Output/SFS/TB_pairwiseFst_matrix.csv", row.names = 1)

df<-pairfst
diag(df)<-0
df$pop<-rownames(df)
dfm<-melt(df,na.rm=T, id.vars='pop')
#NA to diagonal
dfm$value[dfm$value==0]<-NA
dfm$pop<-factor(dfm$pop, levels=pops)
dfm$value<-round(dfm$value, 4)
ggplot(data = dfm, aes(pop, variable, fill = value))+
    geom_tile(color = "white")+
    scale_fill_gradientn(colors=c("white", "#0C54FF"), limits=c(0, (max(dfm$value, na.rm=T)+0.005)),na.value="gray80", 
                         name="Fst")+
    theme_minimal()+ xlab("")+ylab("")+
    theme(axis.text.x = element_text(angle = 0, vjust = 0, 
                                     size = 12, hjust = 0.5))+
    theme(axis.text.y = element_text(size = 12))+
    coord_fixed()+
    geom_text(aes(pop, variable, label = value), color = "black", size = 5)
ggsave(paste0("../Output/SFS/pairwiseFst_TB.png"), width = 5, height = 5, dpi=150)

2.2.4 Fst change over time

# Plot Fst in a bar plot ordered and colored in the same way as Fst/Pi shuffle results (Shuffling_pi.fst.tehat.Rmd)
fsts<-dfm[!is.na(dfm$value),]
fsts$comp<-paste0(fsts$pop,"_",fsts$variable)

#set the colors
#div1<-diverging_hcl(6, palette="Blue-Red")
#div2<-rev(div1)
#names(div2)<-c("PWS96_PWS07","PWS07_PWS17","PWS91_PWS96", "PWS91_PWS07", "PWS91_PWS17","PWS96_PWS17")
fsts<-fsts[order(fsts$value, decreasing = T),]
fsts$comp<-factor(fsts$comp, levels=paste0(unique(fsts$comp)))

ggplot(fsts, aes(x=comp, y=value, fill=comp))+
    geom_bar(stat="identity")+
    scale_fill_manual(values = div1)+
    xlab('')+ylab('Fst')+
    theme_classic()+
    theme(axis.text.x = element_text(angle=45, hjust=1), legend.title = element_blank())
ggsave("../Output/Fst/TB_PairwiseFst_ordered.png", width = 4, height = 2.8, dpi=300 )

#Fst over time
fsts2<-fsts[fsts$comp %in% c("TB91_TB96","TB96_TB06","TB06_TB17"),]
fsts2$time<-1
fsts2$time[fsts2$comp=="TB96_TB06"]<-2
fsts2$time[fsts2$comp=="TB06_TB17"]<-3
fsts2<-fsts2[order(fsts2$time),]
ggplot(fsts2, aes(x=time, y=value))+
    geom_point(size=3, color="steelblue")+
    geom_path( aes(x=time, y=value),color="steelblue")+
    theme_classic()+ylab("Fst")+xlab("")+
    scale_x_continuous(breaks=c(1,2,3), labels=c("1991-1996", "1996-2006","2006-2017"))
ggsave("../Output/Fst/Fst_overTime_TB.png", width = 4, height = 2.8, dpi=300 )

fsts$series<-"1991-2007, 1991-2017"
fsts$series[fsts$comp %in% c("TB91_TB96","TB96_TB06","TB06_TB17")]<-"1991-1996, 1996-2007, 2007-2017"
fsts$series[fsts$comp =="TB96_TB17"]<-"1996-2017"
fsts$time<-1
fsts$time[fsts$variable=="TB17"]<-3
fsts$time[fsts$variable=="TB06"]<-2
#source("../Rscripts/BaseScripts.R")
fsts<-fsts[order(fsts$time),]
ggplot(fsts, aes(x=time, y=value, color=series))+
    geom_point(size=3)+
    geom_path()+
    scale_color_manual(values=cols)+
    theme_classic()+ylab("Fst")+xlab("")+
    scale_x_continuous(breaks=c(1,2,3), labels=c("1991-1996", "~2007","~2017"))+
    theme(legend.title = element_blank())
ggsave("../Output/Fst/Fst_overTime_TB_allComparison.png", width = 6, height = 2.8, dpi=300 )

# plot both PWS and TB together

fstP2$pop<-"PWS"
fsts2$pop<-"TB"
fstPT<-rbind(fstP2, fsts2)

ggplot(fstPT, aes(x=time, y=value, color=pop))+
    geom_point(size=3)+
    geom_path( aes(x=time, y=value))+
    scale_color_manual(values=cols[c(2,1)])+
    theme_classic()+ylab("Fst")+xlab("")+
    scale_x_continuous(breaks=c(1,2,3), labels=c("1991-1996", "1996-2006","2006-2017"))+
    theme(legend.title = element_blank())
ggsave("../Output/Fst/Fst_overTime_PWS_TB.png", width = 4, height = 2.8, dpi=300 )

fstT1<-fsts
fstT2<-fsts2

2.2.5 Mean pairsie Fst per chromosome

# Plot mean Fst of each chromosme
Fst<-data.frame()
for (j in 1:26){
    fst.ch<-fst[fst$ch==j,]
    pairch<-data.frame(matrix(ncol=4, nrow=4), row.names=pops)
    colnames(pairch)<-pops
    for (i in 1:6){
        pop1<-comb[i,1]
        pop2<-comb[i,2]
        df<-fst.ch[fst.ch$pop==compare[i],]
        pairch[pop1,pop2]<-mean(df$Fst, na.rm=T)
    }
    diag(pairch)<-0
    pairch$pop<-rownames(pairch)
    dfm<-melt(pairch,na.rm=T, id.vars='pop')
    
    #NA to diagonal
    dfm$value[dfm$value==0]<-NA
    dfm$pop<-factor(dfm$pop, levels=pops)
    dfm$value<-round(dfm$value, 4)
    dfm$chr<-j
    Fst<-rbind(Fst, dfm)
    
}
Fst$id<-paste0(Fst$pop," vs.",Fst$variable)
Fst<-Fst[!is.na(Fst$value),]
ggplot(Fst, aes(x=chr, y=value,color=id))+
    geom_point()+
    geom_path(stat="identity")+
    theme_minimal()+ylab("Fst")+
    scale_x_continuous(breaks=1:26, labels = 1:26)+
    theme(legend.title = element_blank(), panel.grid.minor.x = element_blank())
ggsave("../Output/SFS/TB_Fst_byChromosome_dotplot.png", width = 13, height=6.5, dpi=150)

TB mean Fst per chromosome


2.3 Sitka Sound

2.3.1 Pairwise Fst along the genome

2.3.2 Pairwise Fst along each chromosome

## Plot Fst values along each chromosome
fst$chr<-factor(fst$chr, levels=paste0("chr",1:26))
fstss<-fst
plots<-list()
compare<-paste0(unique(fstss$pop))
for (i in 1:3){ 
    fs<-gsub("vs.","",compare[i])
    pops <- unlist(strsplit(fs, "\\."))
    maxy<-max(fstss$Fst[fstss$pop==compare[i]])
    # Fst with actual line to highlight the differences
    plots[[i]] <- ggplot(fstss[fstss$pop==compare[i],], aes(x =midPos, y =Fst )) + 
        geom_point(size = 1, color = gry,alpha = 0.4, shape = 1)+
        theme_minimal()+ylim(0,maxy+0.02)+
        theme(axis.text.x=element_blank())+
        ylab("Fst\n")+ xlab("")+ 
        ggtitle(paste0(pops[1]," vs.", pops[2]))+
        geom_line(color=blu, size=0.2)+
        facet_wrap(~chr, ncol = 9)
}

{png(paste0("Output/SFS/SS_Fst_maf00_chr.png"), height = 4, width = 18, res=150, units = "in")  
grid.arrange(plots[[1]], plots[[2]], plots[[3]], ncol=3)  
dev.off()  }

2.3.3 Pairwise Fst matrix

## Continued from the above
pops<-c("SS96","SS06","SS17")
comb<-t(combn(pops,2))

## Plot average fst in a heatmap
compare<-unique(fst$pop)
pairfst<-data.frame(matrix(ncol=3, nrow=3), row.names=pops)
colnames(pairfst)<-pops
for (i in 1:3){
    pop1<-comb[i,1]
    pop2<-comb[i,2]
    df<-fst[fst$pop==compare[i],]
    pairfst[pop1,pop2]<-mean(df$Fst, na.rm=T)
}
write.csv(pairfst,"../Output/SFS/SS_pairwiseFst_matrix.csv")

pairfst<-read.csv("../Output/SFS/SS_pairwiseFst_matrix.csv", row.names = 1)
df<-pairfst
diag(df)<-0
df$pop<-rownames(df)
dfm<-melt(df,na.rm=T, id.vars='pop')
#NA to diagonal
dfm$value[dfm$value==0]<-NA
dfm$pop<-factor(dfm$pop, levels=pops)
dfm$value<-round(dfm$value, 4)
ggplot(data = dfm, aes(pop, variable, fill = value))+
    geom_tile(color = "white")+
    scale_fill_gradientn(colors=c("white", "#0C54FF"), limits=c(0, (max(dfm$value, na.rm=T)+0.005)),na.value="gray80", 
                         name="Fst")+
    theme_minimal()+ xlab("")+ylab("")+
    theme(axis.text.x = element_text(angle = 0, vjust = 0, 
                                     size = 12, hjust = 0.5))+
    theme(axis.text.y = element_text(size = 12))+
    coord_fixed()+
    geom_text(aes(pop, variable, label = value), color = "black", size = 5)
ggsave(paste0("../Output/SFS/pairwiseFst_SS.png"), width = 5, height = 5, dpi=150)

2.3.4 Fst change over time

# Plot Fst in a bar plot ordered and colored in the same way as Fst/Pi shuffle results (Shuffling_pi.fst.tehat.Rmd)
fsts<-dfm[!is.na(dfm$value),]
fsts$comp<-paste0(fsts$pop,"_",fsts$variable)

#set the colors
#div1<-diverging_hcl(6, palette="Blue-Red")
#div2<-rev(div1)
#names(div2)<-c("PWS96_PWS07","PWS07_PWS17","PWS91_PWS96", "PWS91_PWS07", "PWS91_PWS17","PWS96_PWS17")
fsts<-fsts[order(fsts$value, decreasing = T),]
fsts$comp<-factor(fsts$comp, levels=paste0(unique(fsts$comp)))

ggplot(fsts, aes(x=comp, y=value, fill=comp))+
    geom_bar(stat="identity")+
    scale_fill_manual(values = div1)+
    xlab('')+ylab('Fst')+
    theme_classic()+
    theme(axis.text.x = element_text(angle=45, hjust=1), legend.title = element_blank())
ggsave("../Output/Fst/TB_PairwiseFst_ordered.png", width = 3.4, height = 2.8, dpi=300 )

#Fst over time
fsts2<-fsts[fsts$comp %in% c("SS96_SS06","SS06_SS17"),]
fsts2$time<-1
fsts2$time[fsts2$comp=="SS96_SS06"]<-2
fsts2$time[fsts2$comp=="SS06_SS17"]<-3
fsts2<-fsts2[order(fsts2$time),]
ggplot(fsts2, aes(x=time, y=value))+
    geom_point(size=3, color="steelblue")+
    geom_path( aes(x=time, y=value),color="steelblue")+
    theme_classic()+ylab("Fst")+xlab("")+
    scale_x_continuous(breaks=c(1,2,3), labels=c("1991-1996", "1996-2006","2006-2017"))
ggsave("../Output/Fst/Fst_overTime_SS.png", width = 3.5, height = 2.8, dpi=300 )

fsts$series<-"1991-2007, 1991-2017"
fsts$series[fsts$comp =="SS96_SS17"]<-"1996-2017"
fsts$time<-1
fsts$time[fsts$variable=="SS17"]<-3
fsts$time[fsts$variable=="SS06"]<-2
#source("../Rscripts/BaseScripts.R")
fsts<-fsts[order(fsts$time),]
ggplot(fsts, aes(x=time, y=value, color=series))+
    geom_point(size=3)+
    geom_path()+
    scale_color_manual(values=cols)+
    theme_classic()+ylab("Fst")+xlab("")+
    scale_x_continuous(breaks=c(1,2,3), labels=c("1991-1996", "~2007","~2017"))+
    theme(legend.title = element_blank())
ggsave("../Output/Fst/Fst_overTime_SS_allComparison.png", width = 6, height = 2.8, dpi=300 )


# plot all 3 pops together

fstPTS<-rbind(fstPT,fsts2)
write.csv(fstPTS, "../Output/Fst/Mean_Fst_overTime_3pops.csv", row.names = F)


fstPST<-read.csv("../Output/Fst/Mean_Fst_overTime_3pops.csv")

ggplot(fstPST, aes(x=time, y=value, color=pop))+
    geom_point(size=3)+
    geom_path( aes(x=time, y=value))+
    scale_color_manual(values=cols[c(2,1,3)])+
    theme_classic()+ylab("Fst")+xlab("")+
    scale_x_continuous(breaks=c(1,2,3), labels=c("1991-1996", "1996-2006","2006-2017"))+
    theme(legend.title = element_blank())
ggsave("../Output/Fst/Fst_overTime_3Pops.png", width = 5, height = 2.8, dpi=300 )

fstP1$pop<-"PWS"
fstT1$pop<-"TB"
fsts$pop<-"SS"
fsts3<-rbind(fstP1, fstT1, fsts)
write.csv(fsts3, "../Output/Fst/Mean_Fst_overTime_3pops_allcomp.csv")

2.3.5 Mean pairsie Fst per chromosome

# Plot mean Fst of each chromosomes
Fst<-data.frame()
for (j in 1:26){
    fst.ch<-fst[fst$ch==j,]
    pairch<-data.frame(matrix(ncol=3, nrow=3), row.names=pops)
    colnames(pairch)<-pops
    for (i in 1:3){
        pop1<-comb[i,1]
        pop2<-comb[i,2]
        df<-fst.ch[fst.ch$pop==compare[i],]
        pairch[pop1,pop2]<-mean(df$Fst, na.rm=T)
    }
    diag(pairch)<-0
    pairch$pop<-rownames(pairch)
    dfm<-melt(pairch,na.rm=T, id.vars='pop')
    
    #NA to diagonal
    dfm$value[dfm$value==0]<-NA
    dfm$pop<-factor(dfm$pop, levels=pops)
    dfm$value<-round(dfm$value, 4)
    dfm$chr<-j
    Fst<-rbind(Fst, dfm)
    
}
Fst$id<-paste0(Fst$pop," vs.",Fst$variable)
Fst<-Fst[!is.na(Fst$value),]
ggplot(Fst, aes(x=chr, y=value,color=id))+
    geom_point()+
    geom_path(stat="identity")+
    theme_minimal()+ylab("Fst")+
    scale_x_continuous(breaks=1:26, labels = 1:26)+
    theme(legend.title = element_blank(), panel.grid.minor.x = element_blank())
ggsave("../Output/SFS/SS_Fst_byChromosome_dotplot.png", width = 8, height=4.5, dpi=150)

3 Fst between populations (2017)

3.1 Pairiwse Fst along the genome

popsn<-read.csv("../Data/Sample_metadata_892pops.csv")
pops<-unique(popsn$Population.Year)
y17<-pops[grep("17",pops)]

comb<-combn(y17, 2)
comb<-t(comb)

#Year2017
fst17<-data.frame()
for (i in 1: nrow(comb)){
    pop1<-comb[i,1]
    pop2<-comb[i,2]
    df<-read.delim(paste0("../Data/new_vcf/angsd/fromVCF/2D/fst_folded_",pop1,"_",pop2,"_50kWindow_maf00"))
    conames<-colnames(df)[2:4]
    colnames(df)[4]<-"Fst"
    colnames(df)[1:3]<-conames
    df$pop<-paste0(pop1,".vs.",pop2)
    df$ch=as.integer(gsub("chr","", df$chr))
    df<-df[order(df$ch),]
    df$loc<-1:nrow(df)
    fst17<-rbind(fst17, df)
}

write.csv(fst17,"../Output/SFS/Fst_window_year2017_allpops.csv")

fst17$ch<-as.integer(gsub("chr","",fst17$chr))
fst17<-fst17[order(fst17$ch, fst17$midPos),]
fst17$chr<-factor(fst17$chr, levels=paste0("chr",1:26))

pairs<-unique(fst17$pop)
plots<-list()
for (i in 1:length(pairs)){ 
    fs<-gsub(".vs","",pairs[i])
    pops <- unlist(strsplit(fs, "\\."))
    # Fst with actual line to highlight the differences
    df<-fst17[fst17$pop==pairs[i],]
    plots[[i]] <- ggplot(df, aes(x =midPos, y = Fst)) + 
        geom_point(size = 1, color = "gray",alpha = 0.4, shape = 1)+
        theme_minimal()+
        theme(axis.text.x=element_blank())+
        ylab("Fst\n")+ xlab("")+ 
        ggtitle(paste0(pops[1]," vs.", pops[2]))+
        geom_line(color="steelblue", size=0.2)+
        facet_wrap(~chr, ncol = 9)
}

#Same y-axis
plots2<-list()
#TB ylim=0.8
#nonTB 0.6
for (i in 1:length(pairs)){ 
    fs<-gsub(".vs","",pairs[i])
    pops <- unlist(strsplit(fs, "\\."))
    # Fst with actual line to highlight the differences
    df<-fst17[fst17$pop==pairs[i],]
    if (i %in% c(4,8,11,13,15)) ymax=0.8
    else ymax=0.6
    plots2[[i]] <- ggplot(df, aes(x =midPos, y = Fst)) + 
        geom_point(size = 1, color = "gray",alpha = 0.4, shape = 1)+
        theme_minimal()+ylim(0,ymax)+
        theme(axis.text.x=element_blank())+
        ylab("Fst\n")+ xlab("")+ 
        ggtitle(paste0(pops[1]," vs.", pops[2]))+
        geom_line(color="steelblue", size=0.2)+
        facet_wrap(~chr, ncol = 9)
}
{png(paste0("../Output/SFS/Year2017_Fst1.png"), height = 8, width = 20, res=150, units = "in")
do.call(grid.arrange, c(plots[1:6], ncol=3))
dev.off()}

{png(paste0("../Output/SFS/Year2017_Fst2.png"), height = 12, width = 20, res=150, units = "in")
do.call(grid.arrange, c(plots[7:15], ncol=3))
dev.off()}

#plot non-TB
{png(paste0("../Output/SFS/Year2017_Fst_sameYaxis.png"), height = 16, width = 20, res=150, units = "in")
do.call(grid.arrange, c(plots2[c(1,2,3,5,6,7,9,10,12,14)], ncol=3))
dev.off()}

{png(paste0("../Output/SFS/Year2017_Fst_sameYaxis2_TB.png"), height = 12, width = 20, res=150, units = "in")
do.call(grid.arrange, c(plots2[c(4,8,11,13,15)], ncol=3))
dev.off()}

contrast without TB

Contrast against TB pop

3.2 Paiwise Fst matrix

#Plot pairwise Fst values
bcxca <- round(mean(fst17$Fst[fst17$pop=="BC17.vs.CA17"]),4)
bcxpw <- round(mean(fst17$Fst[fst17$pop=="BC17.vs.PWS17"]),4)
caxpw <- round(mean(fst17$Fst[fst17$pop=="CA17.vs.PWS17"]),4)
bcxwa <- round(mean(fst17$Fst[fst17$pop=="BC17.vs.WA17"]),4)
caxwa <- round(mean(fst17$Fst[fst17$pop=="CA17.vs.WA17"]),4)
bcxss <- round(mean(fst17$Fst[fst17$pop=="BC17.vs.SS17"]),4)
bcxtb <- round(mean(fst17$Fst[fst17$pop=="BC17.vs.TB17"]),4)
ssxtb <- round(mean(fst17$Fst[fst17$pop=="SS17.vs.TB17"]),4)
caxss <- round(mean(fst17$Fst[fst17$pop=="CA17.vs.SS17"]),4)
pwxss <- round(mean(fst17$Fst[fst17$pop=="PWS17.vs.SS17"]),4)
caxtb <- round(mean(fst17$Fst[fst17$pop=="CA17.vs.TB17"]),4)
pwxtb <- round(mean(fst17$Fst[fst17$pop=="PWS17.vs.TB17"]),4)
pwxwa <- round(mean(fst17$Fst[fst17$pop=="PWS17.vs.WA17"]),4)
ssxwa <- round(mean(fst17$Fst[fst17$pop=="SS17.vs.WA17"]),4)
tbxwa <- round(mean(fst17$Fst[fst17$pop=="TB17.vs.WA17"]),4)

fst_vec <- c(0,pwxtb,ssxtb,bcxtb,tbxwa,caxtb,
             pwxtb,0,pwxss,bcxpw,pwxwa,caxpw,
             ssxtb,pwxss,0,bcxss,ssxwa,caxss,
             bcxtb,bcxpw,bcxss,0,bcxwa,bcxca,
             tbxwa,pwxwa,ssxwa,bcxwa,0,caxwa,
             caxtb,caxpw,caxss,bcxca,caxwa,0)

fst_mat = matrix(fst_vec, nrow = 6, ncol = 6)
colnames(fst_mat) <- c("TB17","PWS17","SS17","BC17","WA17","CA17")
rownames(fst_mat) <- c("TB17","PWS17","SS17","BC17","WA17","CA17")

fst_mat[lower.tri(fst_mat, diag = F)]<-NA
write.csv(fst_mat, "../Output/SFS/Fst_matrix_2017_all.csv")

# Melt the correlation matrix
melted_cormat <- melt(fst_mat, na.rm = TRUE)
melted_cormat[melted_cormat==0]<-NA
# Heatmap
melted_cormat$color<-"a"
melted_cormat$color[melted_cormat$value>=0.1]<-"b"

ggplot(data = melted_cormat, aes(Var2, Var1, fill = value))+
    geom_tile(color = "white")+
    scale_fill_gradientn(colors=c("white", "blue"), limits=c(0, (max(melted_cormat$value, na.rm=T)+0.005)),na.value="gray80", 
                         name="Fst")+
    theme_minimal()+ xlab("")+ylab("")+
    theme(axis.text.x = element_text(angle = 0, vjust = 0, 
                                     size = 12, hjust = 0.5))+
    theme(axis.text.y = element_text(size = 12))+
    coord_fixed()+
    geom_text(aes(Var2, Var1, label = value, color=color),  size = 5)+
    scale_color_manual(values=c("black", "white"), guide='none')
ggsave("../Output/SFS/Fst_matrix_2017_all.png", height = 6, width = 6, dpi=150)

3.3 Fst change over time between PWS/SS/TB

comb<-data.frame(a=c("PWS91","PWS96","PWS07","PWS17","PWS96","PWS07","PWS17","SS96","SS06","SS17"),b=c("TB91","TB96","TB06","TB17","SS96","SS06","SS17","TB96","TB06","TB17")) 

fsts<-data.frame()
for (i in 1: nrow(comb)){
    pop1<-comb[i,1]
    pop2<-comb[i,2]
    df<-read.delim(paste0("../Data/new_vcf/angsd/fromVCF/2D/fst_folded_",pop1,"_",pop2,"_50kWindow_maf00"))
    conames<-colnames(df)[2:4]
    colnames(df)[4]<-"Fst"
    colnames(df)[1:3]<-conames
    df$pop<-paste0(pop1,".vs.",pop2)
    df$ch=as.integer(gsub("chr","", df$chr))
    df<-df[order(df$ch),]
    df$loc<-1:nrow(df)
    fsts<-rbind(fsts, df)
}
write.csv(fsts,"../Output/SFS/Fst_betweenPop.csv")

re<-aggregate(fsts$Fst, by=list(fsts$pop), mean, na.rm=T)
compa<-strsplit(re$Group.1, split=".vs.")
re$pop1<-lapply(compa, "[[", 1)
re$pop2<-lapply(compa, "[[", 2)
re$year <- as.numeric(str_extract(re$pop1, "[0-9]+"))
re$year[re$year==7|re$year==6]<-2006
re$year[re$year==91]<-1991
re$year[re$year==96]<-1996
re$year[re$year==17]<-2017
re$pop1<-str_extract(re$pop1, "[aA-zZ]+")
re$pop2<-str_extract(re$pop2, "[aA-zZ]+")
re$pops<-paste0(re$pop1,"-",re$pop2)


colors2<-brewer.pal(n=8, "Set3")
"#8DD3C7" "#FFFFB3" "#BEBADA" "#FB8072" "#80B1D3" "#FDB462" "#B3DE69" "#FCCDE5"


ggplot(re, aes(x=year, y=x, color=pops, group=pops))+
    geom_point(position=position_dodge(width = 1), size=3)+
    geom_line(position=position_dodge(width = 1))+
    ylab("Fst")+xlab("Year")+
    theme_classic()+theme(legend.title = element_blank())+
    scale_color_manual(values=colors2[c(4,1,3)])
ggsave("../Output/SFS/Fst_shift_overYears_3pops.png", width = 5, height = 3, dpi=300)



4 Use Pixy to calculate pi

4.1 Steps

  1. Create all sites (invariant) vcf files
    (see invariantVCF_PWS91.sh)
#Using bcftools mpileup (-r is to specify chromosome)
bcftools mpileup -f <reference.fa> -b <bamlist.txt> -r <X> | bcftools call -m -Oz -f GQ -o <output>

#Create a sample id file (required)
# Add population info to the sample sheet
sed 's/$/\tPWS91/' PWS91.txt >pws91pop.txt

#check the sample names in the vcf file
bcftools query -l PWS91_ch1.vcf.gz
# somehow, _ was replaced by .
  1. Reformat the sample file (’_’ was replaced by ‘.’ in the process of making vcf files)
pops<-c("PWS91","PWS96","PWS07","PWS17")
for (i in 1: length(pops)){
    df<-read.table(paste0("../Data/pixy/",pops[i],".txt"))
    df$V1<-gsub("_",".", df$V1)
    df$V2<-pops[i]
    write.table(df, paste0("../Data/pixy/",pops[i],"pop.txt"), quote = F, col.names=F, row.names = F, sep="\t")
}

pops<-c("TB91","TB96","TB06","TB17")
for (i in 1: length(pops)){
    df<-read.table(paste0("../Data/pixy/",pops[i],".txt"))
    df$V1<-gsub("_",".", df$V1)
    df$V2<-pops[i]
    write.table(df, paste0("../Data/pixy/",pops[i],"/" ,pops[i],"pop.txt"), quote = F, col.names=F, row.names = F, sep="\t")
}

pops<-c("SS96","SS06","SS17")
for (i in 1: length(pops)){
    df<-read.table(paste0("../Data/popinfo/",pops[i],".txt"))
    df$V1<-gsub("_",".", df$V1)
    df$V2<-pops[i]
    write.table(df, paste0("../Data/pixy/",pops[i],"/" ,pops[i],"pop.txt"), quote = F, col.names=F, row.names = F, sep="\t")
}
pops<-c("CA17","BC17","WA17")
for (i in 1: length(pops)){
    df<-read.table(paste0("../Data/popinfo/",pops[i],".txt"))
    df$V1<-gsub("_",".", df$V1)
    df$V2<-pops[i]
    write.table(df, paste0("../Data/pixy/",pops[i],"/" ,pops[i],"pop.txt"), quote = F, col.names=F, row.names = F, sep="\t")
}
  1. Run Pixy (example: PWS91 Chr1)
#index the vcf.gz file
tabix PWS91_ch1.vcf.gz

# Run Pixy 
#first activate the conda env (py38) -runs on older Python (<=3.8)
conda activate py38
cd ~/Projects/PacHerring/Data/pixy
pixy --stats pi --vcf PWS91_ch1.vcf.gz --populations pws91pop.txt --window_size 10000 --n_core 8 --output_prefix PWS91_ch1

conda deactivate
  1. Summarize the output from Pixy for PWS91 Chr1
pipi<-read.table("../Data/pixy/PWS91/PWS91_ch1_pi.txt", header=T)
ggplot(pipi, aes(x=window_pos_1, y=avg_pi))+
    geom_line(color=blu)+xlab('')+ylab(expression("mean "*pi))
ggsave("../Output/SFS/pixy_pi_pws91_ch1_line.png", width = 6, height = 3.5, dpi=300)

ggplot(pipi, aes(x=window_pos_1, y=avg_pi))+
    geom_point(size=0.3, color="gray20")

mean(pipi$avg_pi)
# 0.00278471

#weighted mean
pipi$pi_sum<-pipi$avg_pi*pipi$no_sites
sum(pipi$pi_sum)/sum(pipi$no_sites)
# 0.002775464

4.2 Compare π estimated from ANGSD vs. Pixy

#Compare with the pi estimated from ANGSD SFS 
theta<-read.delim(paste0('../Data/new_vcf/angsd/fromBam/unfolded/PWS91_50kwin_10kstep.pestPG'))
theta$pi<-theta$tP/theta$nSites
mean(theta$pi[theta$Chr=="chr1"])
#0.003826297

#chr1 comparison
ch1<-pipi[,c("chromosome", "avg_pi")]
ch1$method<-"Pixy"
theta2<-theta[,c("Chr","pi")]
theta2$method<-"ANGSD"
colnames(ch1)[1:2]<-c("Chr","pi")
ch1<-rbind(ch1,theta2)


ggplot(ch1, aes(x=method, y=pi))+
    geom_boxplot(aes(middle=mean(pi), color=method),outlier.alpha = 0.2)+
    theme_classic()+xlab('')+ylab(expression(pi))+
    scale_color_manual(values=c("#1f78b4","#fb9a99"), guide='none')
ggsave("../Output/SFS/Pi_comparison_pixy.vs.angsd.pws91.ch1.png", width=4, height=4,dpi=200 )

4.2.1 Run Pixy for all chromosomes for PWS

#index vcf files for all chromosomes
for f in *.vcf.gz; do
filename=$(basename $f)
tabix $f 
done
#create a script to run pixy
for (j in 1: length(pops)){
    sink(paste0("../Data/pixy/runpixy_", pops[j],".sh"))
    cat("#!/bin/bash\n\n")
    for (i in 1:26){
        cat(paste0("pixy --stats pi --vcf ",pops[j],"_ch",i,".vcf.gz --populations ",pops[j],"pop.txt --window_size 10000 --n_core 8 --output_prefix ",pops[j], "_ch",i, "\n"))
    }
    sink(NULL)
}

4.2.2 Plot the outputs from Pixy for all PWS groups

#read the output file for PWS:
pops<-c("PWS91","PWS96","PWS07","PWS17")

for (p in 1 : length(pops)){
    pixy<-data.frame()
    for (i in 1:26){
        df<-read.table(paste0("../Data/pixy/",pops[p],"/",pops[p],"_ch",i,"_pi.txt"), header=T)
        df$method<-"Pixy"
        df$WinCenter<-df$window_pos_2-5000
        df<-df[,c("chromosome","WinCenter","avg_pi","method")]
        colnames(df)[c(1,3)]<-c("Chr","pi")
        pixy<-rbind(pixy, df)
    }
    write.csv(pixy, paste0("../Output/Pi/",pops[p], "_Pi_pixy_per50kWindow.csv"))
    
    #Compare with the pi estimated from ANGSD SFS 
    theta<-read.delim(paste0('../Data/new_vcf/angsd/fromBam/unfolded/',pops[p],'_50kwin_10kstep.pestPG'))
    theta$pi<-theta$tP/theta$nSites
    theta$method<-"ANGSD"
    pi<-rbind(pixy, theta[,c("Chr","WinCenter","pi","method")])

    pi$Chr<-factor(pi$Chr, levels=paste0("chr",1:26))
    ggplot(pi, aes(x=Chr, y=pi, color=method))+
        geom_boxplot(aes(middle=mean(pi)),outlier.alpha = 0.2, outlier.size = 0.6)+
        theme_classic()+theme(axis.text.x = element_text(angle=45, hjust =1))+
        xlab("")+ylab(expression(pi))+ggtitle(pops[p])+
        scale_color_manual(values=c("#1f78b4","#fb9a99"))
    ggsave(paste0("../Output/Pi/Pi_comparison_pixy.vs.angsd.",pops[p], ".png"), width = 10, height = 5, dpi=100)
    
    # genome-wide mean pi comparison
    means <- aggregate(pi ~  method, pi, mean)
    
    ggplot(pi, aes(x=method, y=pi))+
        geom_boxplot(aes(color=method), outlier.alpha = 0.2, outlier.size = 0.6)+
        theme_classic()+ ggtitle(pops[p])+
        geom_point(stat = "summary", fun = "mean", color="gray40")+
         xlab("")+ylab(expression(pi))+
        scale_color_manual(values=c("#1f78b4","#fb9a99"), guide='none')+
        geom_text(data = means, aes(label = round(pi, digits=5), y = pi + 0.02), color="gray40")
    ggsave(paste0("../Output/Pi/Pi_comparison_pixy.vs.angsd_mean_",pops[p],".png"), width = 3, height = 3, dpi=200)
}

PWS91

PWS07

PWS17

  • Pixy estimates have more variability
  • Pixy esitmates are slightly lower than ANSGD estiamtes
# Assess the differences between ANGSD and Pixy
pops<-c("PWS91","PWS96","PWS07","PWS17")
diff<-data.frame(pop=pops)
for (p in 1 : length(pops)){
    pixy<-data.frame()
    for (i in 1:26){
        df<-read.table(paste0("../Data/pixy/",pops[p],"/",pops[p],"_ch",i,"_pi.txt"), header=T)
        df$method<-"Pixy"
        df$WinCenter<-df$window_pos_2-5000
        df<-df[,c("chromosome","WinCenter","avg_pi","method")]
        colnames(df)[c(1,3)]<-c("Chr","pi")
        pixy<-rbind(pixy, df)
    }
    #mean.pixy<-aggregate(pixy$pi, by=list(pixy$Chr), mean, na.rm=T)
    
    #Pi estimated from ANGSD SFS 
    theta<-read.delim(paste0('../Data/new_vcf/angsd/fromBam/unfolded/',pops[p],'_50kwin_10kstep.pestPG'))
    theta$pi<-theta$tP/theta$nSites
    theta$method<-"ANGSD"
    pi<-rbind(pixy, theta[,c("Chr","WinCenter","pi","method")])

    means<-aggregate(pi$pi, by=list(pi$method), mean, na.rm=T)
    
    #differences in pi estimates
    
    diff$prop.difference[p]<-means$x[means$Group.1=="ANGSD"]/means$x[means$Group.1=="Pixy"]
}


knitr::kable(diff)
pops<-c("PWS91","PWS96","PWS07","PWS17")
Pi<-data.frame()
for (i in 1:length(pops)){
    #pixy
    pi<-read.csv(paste0("../Output/Pi/",pops[i], "_Pi_pixy_per50kWindow.csv"), row.names =1 )
    pi$Chr<-factor(pi$Chr, levels=paste0("chr",1:26))
    pi$pop<-pops[i]
    Pi<-rbind(Pi,pi)
    
    theta<-read.delim(paste0('../Data/new_vcf/angsd/fromBam/unfolded/',pops[i],'_50kwin_10kstep.pestPG'))
    theta$pi<-theta$tP/theta$nSites
    theta$pop<-pops[i]
    theta$method<-"ANGSD"
    theta<-theta[,c("Chr", "WinCenter","pi","method","pop")]    
    Pi<-rbind(Pi, theta)
}

Pi$pop<-factor(Pi$pop, levels=pops)

# genome-wide mean pi comparison
means <- aggregate(Pi$pi, by=list(Pi$method, Pi$pop), mean, na.rm=T)
colnames(means)<-c("method","pop", "pi")
ggplot(Pi, aes(x=pop, y=pi, color=method))+
    geom_boxplot(position=position_dodge(width=0.8),  outlier.alpha = 0.2, outlier.size = 0.6)+
    theme_classic() + ylim(0,0.045)+
    stat_summary(fun = "mean", geom = "point", position=position_dodge(width=0.8), shape=16)+
    xlab("")+ylab(expression(pi))+
    scale_color_manual(values=c("#1f78b4","#fb9a99"))+
    annotate(geom="text", x=as.vector(sapply(1:4, function(x) c(x-.2, x+.2))), y=rep(c(0.018, 0.02),times=4), label=round(means$pi, digits=5), size=2.5)

ggsave(paste0("../Output/Pi/Pi_comparison_pixy.vs.angsd_mean_PWS.png"), width =6, height = 3, dpi=300)

ggplot(Pi, aes(x=pop, y=pi, color=method))+
    geom_boxplot(position=position_dodge(width=0.8),  outlier.alpha = 0.2, outlier.size = 0.6)+
    theme_classic() +ylim(0,0.015)+
    stat_summary(fun = "mean", geom = "point", position=position_dodge(width=0.8), shape=16)+
    xlab("")+ylab(expression(pi))+
    scale_color_manual(values=c("#1f78b4","#fb9a99"))
    annotate(geom="text", x=as.vector(sapply(1:4, function(x) c(x-.2, x+.2))), y=rep(c(0.018, 0.02),times=4), label=round(means$pi, digits=5), size=2)

ggsave(paste0("../Output/Pi/Pi_comparison_pixy.vs.angsd_mean_PWS_zoomed.png"), width =6.7, height = 3, dpi=300)

4.2.3 Compare across years -PWS

pops<-c("PWS91","PWS96","PWS07","PWS17")
Pi<-data.frame()
for (i in 1:length(pops)){
    pi<-read.csv(paste0("../Output/Pi/",pops[i], "_Pi_pixy_per50kWindow.csv"), row.names =1 )
    pi$Chr<-factor(pi$Chr, levels=paste0("chr",1:26))
    pi$pop<-pops[i]
    Pi<-rbind(Pi,pi)
}

Pi$pop<-factor(Pi$pop, levels=pops)

means <- aggregate(pi ~ pop,Pi, mean)
colnames(means)<-c("method","pop", "pi")
ggplot(Pi, aes(x=pop, y=pi, color=pop))+
        geom_boxplot(aes(color=pop), outlier.alpha = 0.2, outlier.size = 0.6)+
        theme_classic()+ ggtitle("PWS")+
        geom_point(stat = "summary", fun = "mean", color="gray40")+
         xlab("")+ylab(expression(pi))+
        geom_text(data = means, aes(label = round(pi, digits=5), y = pi + 0.02), color="gray40")
ggsave(paste0("../Output/Pi/Pi_pixy_mean.",pops[i],".png"), width = 4.5, height = 3, dpi=200)

#read the output file for each pops:
pops<-c("TB91","TB96","TB06","TB17")

for (p in 1 : length(pops)){
    pixy<-data.frame()
    for (i in 1:26){
        df<-read.table(paste0("../Data/pixy/",pops[p],"/",pops[p],"_ch",i,"_pi.txt"), header=T)
        df$method<-"Pixy"
        df$WinCenter<-df$window_pos_2-5000
        df<-df[,c("chromosome","WinCenter","avg_pi","method")]
        colnames(df)[c(1,3)]<-c("Chr","pi")
        pixy<-rbind(pixy, df)
    }
    write.csv(pixy, paste0("../Output/Pi/",pops[p], "_Pi_pixy_per50kWindow.csv"))
}

Pi<-data.frame()
for (i in 1:length(pops)){
    pi<-read.csv(paste0("../Output/Pi/",pops[i], "_Pi_pixy_per50kWindow.csv"), row.names =1 )

    pi$Chr<-factor(pi$Chr, levels=paste0("chr",1:26))
    ggplot(pi, aes(x=Chr, y=pi))+
        geom_boxplot(aes(middle=mean(pi)),outlier.alpha = 0.2, outlier.size = 0.6,color="#1f78b4")+
        theme_classic()+theme(axis.text.x = element_text(angle=45, hjust =1))+
        xlab("")+ylab(expression(pi))+ggtitle(pops[i])
    ggsave(paste0("../Output/Pi/Pi_pixy.perChrom.",pops[i], ".png"), width = 8.5, height = 5, dpi=300)
    
    pi$pop<-pops[i]
    Pi<-rbind(Pi,pi)
}

Pi$pop<-factor(Pi$pop, levels=pops)
means <- aggregate(pi ~ pop,Pi, mean)
ggplot(Pi, aes(x=pop, y=pi, color=pop))+
        geom_boxplot(aes(color=pop), outlier.alpha = 0.2, outlier.size = 0.6)+
        theme_classic()+ ggtitle("TB")+
        geom_point(stat = "summary", fun = "mean", color="gray40")+
         xlab("")+ylab(expression(pi))+
        geom_text(data = means, aes(label = round(pi, digits=5), y = pi + 0.02), color="gray40")
ggsave(paste0("../Output/Pi/Pi_pixy_mean.TB.png"), width = 4.5, height = 3, dpi=200)

pops<-c("PWS91","PWS96","PWS07","PWS17","TB91","TB96","TB06","TB17","SS96","SS06","SS17")
year<-c(1991,1996,2007,2017,1991,1996,2006,2017,1996,2006,2017)
meanPi<-data.frame(pop.yr=pops, year=year)
for (i in 1:length(pops)){
    df<-read.csv(paste0("../Output/Pi/",pops[i], "_Pi_pixy_per50kWindow.csv"), row.names =1 )
    meanPi$mean[i]<-mean(df$pi, na.rm=T)
    meanPi$pop[i]<-gsub("\\d.+","",pops[i])
}


ggplot(meanPi, aes(x=year, y=mean, color=pop))+
    geom_point(size=3)+
    geom_line()+
    xlab("")+ylab(paste0("Mean ",expression(pi)))+
    theme_linedraw()+
    scale_color_manual(values=cols[c(2,1,5)])
ggsave("../Output/Pi/Pi_overYears.PWS.TB.SS.png", width = 6, height = 4, dpi=300)

4.2.4 Bootstrap pi values to get 95% CI

# average theta values across sites

#############
# Parameters
#############
# number of chromosomes in each sample
nchr=26
nboot <- 1000

####################
# load functions
require(data.table)
require(boot) # for bootstrap CIs


# For Tajima's D calcs. After https://github.com/ANGSD/angsd/blob/master/misc/stats.cpp
a1f <- function(nsam) return(sum(1/seq(1, nsam-1)))
a2f <- function(nsam) return(sum(1/(seq(1, nsam-1)*seq(1, nsam-1))))
b1f <- function(nsam) return((nsam + 1)/(3*(nsam-1)))
b2f <- function(nsam) return((2*(nsam*nsam + nsam + 3))/(9*nsam*(nsam - 1)))
c1f <- function(a1, b1) return(b1 - (1/a1))
c2f <- function(nsam, a1, a2, b2) return(b2 - ((nsam + 2)/(a1*nsam)) + (a2/(a1 * a1)))
e1f <- function(a1, c1) return(c1/a1)
e2f <- function(a1, a2, c2) return(c2/((a1*a1) + a2))

# Tajima's D calculation
# nsam: sample size
# thetaW: Watterson's theta (# segregating sites / a1)
# sumk: theta pi (average number of SNPs in pairwise comparisons)
# after https://github.com/ANGSD/angsd/blob/master/misc/stats.cpp
tajd <- function(nsam, thetaW, sumk){
    a1 <- a1f(nsam)
    segsites <- thetaW * a1
    if(segsites == 0) return(0)
    a2 <- a2f(nsam)
    b1 <- b1f(nsam)
    b2 <- b2f(nsam)
    c1 <- c1f(a1, b1)
    c2 <- c2f(nsam, a1, a2, b2)
    e1 <- e1f(a1, c1)
    e2 <- e2f(a1, a2, c2)
    res <- (sumk - (thetaW))/sqrt((e1*segsites) + ((e2*segsites)*(segsites-1)))
    return(res)
}

# calc thetas
calcthetas <- function(dat, nchr, nloci){
    # calc ave theta
    thetas <- as.numeric(dat[, .(tW = sum(exp(Watterson)/nloci, na.rm = TRUE), tP = sum(exp(Pairwise)/nloci, na.rm = TRUE))])

    # calculate Tajima's D
    thetas[3] <- tajd(nchr, thetas[1], thetas[2])
    
    #return
    names(thetas) <- c('tW', 'tP', 'tD')
    return(thetas)
}

# calculate stats from specified LGs for block bootstrapping across LGs
thetablock <- function(lgs, indices, alldata, nchr, regs){
    # make bootstrapped dataset
    mydata <- do.call("rbind", lapply(indices, function(n) subset(alldata, Chromo==lgs[n])))
    
    # calculate number of callable loci, given the LGs in this bootstrapped sample
    nloci <- regs[Chromo %in% lgs, .(len = Pos2 - Pos1 + 1), by = .(Chromo, Pos1)][, sum(len)] # sum of bp in the callable region
    
    # calc thetas
    thetas <- calcthetas(mydata, nchr, nloci)
    
    # return
    return(thetas)
}

#using window based angsd file (use preknown loci in 50000 windows)
thetablock2 <- function(lgs, indices, alldata, nchr, regs){
    # make bootstrapped dataset
    mydata <- do.call("rbind", lapply(indices, function(n) subset(alldata, Chromo==lgs[n])))
    
    # calculate number of callable loci, given the LGs in this bootstrapped sample
    #nloci <- regs[Chromo %in% lgs, .(len = Pos2 - Pos1 + 1), by = .(Chromo, Pos1)][, sum(len)] # sum of bp in the callable region

    nloci <- alldata[Chromo %in% lgs,sum(nSites)] # sum of bp in the callable region
    
    # calc thetas
    thetas <- calcthetas(mydata, nchr, nloci)
    
    # return
    return(thetas)
}


######################
# Load data
######################
alldata<-dat
# load all loci theta calcs
dat<-fread('../Data/new_vcf/angsd/fromVCF/BC17_maf00.thetas50kWindow.gz.pestPG')
setnames(dat, 'Chr', 'Chromo')

datCan40 <- fread('analysis/thetas.Can_40.pestPG.gz')
datCan14 <- fread('analysis/thetas.Can_14.pestPG.gz')
datLof07 <- fread('analysis/thetas.Lof_07.pestPG.gz')
datLof11 <- fread('analysis/thetas.Lof_11.pestPG.gz')
datLof14 <- fread('analysis/thetas.Lof_14.pestPG.gz')

# gatk loci
datCan40gatk <- fread('analysis/thetas.Can_40.gatk.pestPG.gz')
datCan14gatk <- fread('analysis/thetas.Can_14.gatk.pestPG.gz')
datLof07gatk <- fread('analysis/thetas.Lof_07.gatk.pestPG.gz')
datLof11gatk <- fread('analysis/thetas.Lof_11.gatk.pestPG.gz')
datLof14gatk <- fread('analysis/thetas.Lof_14.gatk.pestPG.gz')

# fix name
setnames(datCan40, '#Chromo', 'Chromo')
setnames(datCan14, '#Chromo', 'Chromo')
setnames(datLof07, '#Chromo', 'Chromo')
setnames(datLof11, '#Chromo', 'Chromo')
setnames(datLof14, '#Chromo', 'Chromo')

setnames(datCan40gatk, '#Chromo', 'Chromo')
setnames(datCan14gatk, '#Chromo', 'Chromo')
setnames(datLof07gatk, '#Chromo', 'Chromo')
setnames(datLof11gatk, '#Chromo', 'Chromo')
setnames(datLof14gatk, '#Chromo', 'Chromo')

windownames<-colnames(dat)[1]
colnames(dat)[1]<-"window"
## list of callable regions

dat$window<-gsub("\\(",'', dat$window)
dat$window<-gsub("\\)$",'', dat$window)
dat$window<-gsub("\\)",',', dat$window)
windows1<-str_split_fixed(dat$window,",",6) 
colnames(windows1)<-c('IndexStart', 'IndexStop','firstPos_withData','lastPos_withData','WinStart','WinStop')

dat<-cbind(windows1, dat)

regs<-dat[,c("Chromo","WinStart","WinStop")]
names(regs)<-c('Chromo', 'Pos1', 'Pos2')
#regs <- fread('data_2020.05.07/Callable_bases_gadmor2.bed')
#setnames(regs, c('Chromo', 'Pos1', 'Pos2'))
#
## list of no damage sites
#nodam <- fread('data_2020.05.07/GATK_filtered_SNP_no_dam2.tab')
#setnames(nodam, c('Chromo', 'Pos', 'REF', 'ALT'))
#
#
## remove unplaced
#datCan40 <- datCan40[grep('Unplaced', Chromo, invert = TRUE), ]
#datCan14 <- datCan14[grep('Unplaced', Chromo, invert = TRUE), ]
#datLof07 <- datLof07[grep('Unplaced', Chromo, invert = TRUE), ]
#datLof11 <- datLof11[grep('Unplaced', Chromo, invert = TRUE), ]
#datLof14 <- datLof14[grep('Unplaced', Chromo, invert = TRUE), ]
#
#datCan40gatk <- datCan40gatk[grep('Unplaced', Chromo, invert = TRUE), ]
#datCan14gatk <- datCan14gatk[grep('Unplaced', Chromo, invert = TRUE), ]
#datLof07gatk <- datLof07gatk[grep('Unplaced', Chromo, invert = TRUE), ]
#datLof11gatk <- datLof11gatk[grep('Unplaced', Chromo, invert = TRUE), ]
#datLof14gatk <- datLof14gatk[grep('Unplaced', Chromo, invert = TRUE), ]

regs <- regs[Chromo != 'Unplaced', ]
nodam <- nodam[Chromo != 'Unplaced', ]

###################################################
# create table of loci trimmed to no damage sites
###################################################

datCan40gatknd <- merge(datCan40, nodam[, .(Chromo, Pos)], by = c('Chromo', 'Pos')) # trim
datCan14gatknd <- merge(datCan14, nodam[, .(Chromo, Pos)], by = c('Chromo', 'Pos')) # trim
datLof07gatknd <- merge(datLof07, nodam[, .(Chromo, Pos)], by = c('Chromo', 'Pos')) # trim
datLof11gatknd <- merge(datLof11, nodam[, .(Chromo, Pos)], by = c('Chromo', 'Pos')) # trim
datLof14gatknd <- merge(datLof14, nodam[, .(Chromo, Pos)], by = c('Chromo', 'Pos')) # trim


################################
# Run theta calculations
################################
#nloci <- regs[, .(len = Pos2 - Pos1 + 1), by = .(Chromo, Pos1)][, sum(len)] # sum of bp in the callable region

nloci<-dat$nSites

# all loci
calcthetas(dat, nchr, nloci)
calcthetas(datCan14, nchrCan14, nloci)
calcthetas(datLof07, nchrLof07, nloci)
calcthetas(datLof11, nchrLof11, nloci)
calcthetas(datLof14, nchrLof14, nloci)

# gatk loci
calcthetas(datCan40gatk, nchrCan40, nloci)
calcthetas(datCan14gatk, nchrCan14, nloci)
calcthetas(datLof07gatk, nchrLof07, nloci)
calcthetas(datLof11gatk, nchrLof11, nloci)
calcthetas(datLof14gatk, nchrLof14, nloci)

# gatk no damage loci
calcthetas(datCan40gatknd, nchrCan40, nloci)
calcthetas(datCan14gatknd, nchrCan14, nloci)
calcthetas(datLof07gatknd, nchrLof07, nloci)
calcthetas(datLof11gatknd, nchrLof11, nloci)
calcthetas(datLof14gatknd, nchrLof14, nloci)




# block bootstrapping across LGs

#lgs <- datCan40[, sort(unique(Chromo))]
datlist <- list(datCan40, datCan14, datLof07, datLof11, datLof14, 
                datCan40gatk, datCan14gatk, datLof07gatk, datLof11gatk, datLof14gatk,
                datCan40gatknd, datCan14gatknd, datLof07gatknd, datLof11gatknd, datLof14gatknd)
names(datlist) <- c('Can40 all loci', 'Can14 all loci', 'Lof07 all loci', 'Lof11 all loci', 'Lof14 all loci', 
                    'Can40 gatk loci', 'Can14 gatk loci', 'Lof07 gatk loci', 'Lof11 gatk loci', 'Lof14 gatk loci',
                    'Can40 gatk no dam loci', 'Can14 gatk no dam loci', 'Lof07 gatk no dam loci', 'Lof11 gatk no dam loci', 
                    'Lof14 gatk no dam loci')
nchrlist <- list(nchrCan40, nchrCan14, nchrLof07, nchrLof11, nchrLof14, nchrCan40, nchrCan14, nchrLof07, nchrLof11, nchrLof14, nchrCan40, nchrCan14, nchrLof07, nchrLof11, nchrLof14)

thetabootout <- data.frame(type = names(datlist), tW = NA, tWl95 = NA, tWu95 = NA, tP = NA, tPl95 = NA, tPu95 = NA, tD = NA, tDl95 = NA, tDu95 = NA)


#####

lgs <- dat[, sort(unique(Chromo))]

bootlg <- boot(lgs, thetablock2, nboot,  alldata = dat, nchr = nchr, regs = regs)


for(i in 1:length(datlist)){
    print(names(datlist)[i])
    
    
    bootlg <- boot(lgs, thetablock, nboot,  alldata = datlist[[i]], nchr = nchrlist[[i]], regs = regs)
    
    print(bootlg)
    ciW <- boot.ci(bootlg, type = c('perc'), index = 1)
    ciP <- boot.ci(bootlg, type = c('perc'), index = 2)
    ciD <- boot.ci(bootlg, type = c('perc'), index = 3)
    
    thetabootout$tW[i] <- bootlg$t0[1] # the point estimates
    thetabootout$tP[i] <- bootlg$t0[2]  
    thetabootout$tD[i] <- bootlg$t0[3]

    thetabootout$tWl95[i] <- ciW$percent[4] # the confidence intervals
    thetabootout$tWu95[i] <- ciW$percent[5]

    thetabootout$tPl95[i] <- ciP$percent[4]
    thetabootout$tPu95[i] <- ciP$percent[5]

    thetabootout$tDl95[i] <- ciD$percent[4]
    thetabootout$tDu95[i] <- ciD$percent[5]
}

# save
write.csv(thetabootout, file = 'analysis/thetas.boot.cis.csv')

5 Fst between populations in 1991, 1996 and 2006/7

# 1. Y1996
pops<-c("PWS96","SS96","TB96")
comb<-t(combn(pops,2))

fst<-data.frame()
for (i in 1: nrow(comb)){
    pop1<-comb[i,1]
    pop2<-comb[i,2]
    df<-read.delim(paste0("../Data/new_vcf/angsd/fromVCF/2D/fst_folded_",pop1,"_",pop2,"_50kWindow_maf00"))
    conames<-colnames(df)[2:4]
    colnames(df)[4]<-"Fst"
    colnames(df)[1:3]<-conames
    df$pop<-paste0(pop1,".vs.",pop2)
    df$ch=as.integer(gsub("chr","", df$chr))
    df<-df[order(df$ch),]
    df$loc<-1:nrow(df)
    fst<-rbind(fst, df)
}

evens<-paste0("chr",seq(2,26, by=2))
#Plot Fst values across Genome
fst$color<-"col1"
fst$color[fst$chr %in% evens]<-"col2"
fst$pop<-factor(fst$pop, levels=unique(fst$pop))

#add chromosome number
df<-fst[fst$pop=="PWS96.vs.SS96",]
rows<-data.frame(chr=1:26)
for (i in 1:26){
    if (i ==1){
        rows$n[i]<-nrow(df[df$ch==i,])
        rows$middle[i]<-nrow(df[df$ch==i,])/2
    }
    if (i >1){
        rows$n[i]<-nrow(df[df$ch==i,])
        rows$middle[i]<-sum(rows$n[1:(i-1)])+rows$n[i]/2
    }
}

ggplot(fst, aes(x=loc, y=Fst, color=color))+
    facet_wrap(~pop, ncol = 1, strip.position="right")+
    geom_point(size=0.2, alpha=0.6)+
    scale_color_manual(values=c("gray60","steelblue"))+
    theme_bw()+ggtitle("1996")+
    ylab("Fst")+xlab('Genome position')+
    theme(legend.position = "none", panel.grid.major.x = element_blank(), panel.grid.minor.x = element_blank())+
    scale_x_continuous(breaks=rows$middle, labels=1:26)
ggsave("../Output/SFS/Y1996_Fst_pairwise_comparison.png", width = 16, height = 7, dpi=300)


compare<-unique(fst$pop)
pairfst<-data.frame(matrix(ncol=3, nrow=3), row.names=c("TB96","PWS96","SS96"))
colnames(pairfst)<-c("TB96","PWS96","SS96")
for (i in 1:3){
    pop1<-comb[i,1]
    pop2<-comb[i,2]
    df<-fst[fst$pop==compare[i],]
    pairfst[pop1,pop2]<-mean(df$Fst, na.rm=T)
    pairfst[pop2,pop1]<-mean(df$Fst, na.rm=T)
}
write.csv(pairfst,"../Output/SFS/Y1996_pairwiseFst_matrix.csv")

#df<-read.csv("../Output/SFS/Y1996_pairwiseFst_matrix.csv", row.names = 1)
df<-pairfst
diag(df)<-0
df[lower.tri(df)]<-NA
df$pop<-rownames(df)
dfm<-melt(df,na.rm=T, id.vars='pop')
#NA to diagonal
dfm$value[dfm$value==0]<-NA
dfm$pop<-factor(dfm$pop, levels=c("TB96","PWS96","SS96"))
dfm$value<-round(dfm$value, 4)
ggplot(data = dfm, aes(pop, variable, fill = value))+
    geom_tile(color = "white")+
    scale_fill_gradientn(colors=c("white", "#0C54FFCC"), limits=c(0, (max(dfm$value, na.rm=T)+0.05)),na.value="gray80", 
                         name="Fst")+
    theme_minimal()+ xlab("")+ylab("")+
    theme(axis.text.x = element_text(angle = 0, vjust = 0, 
                                     size = 12, hjust = 0.5))+
    theme(axis.text.y = element_text(size = 12))+
    coord_fixed()+
    geom_text(aes(pop, variable, label = value), color = "black", size = 5)
ggsave(paste0("../Output/SFS/Y1996_pairwiseFst.png"), width = 5, height = 5, dpi=300)

# 2. Y2006/2007
pops<-c("PWS07","SS06","TB06")
comb<-t(combn(pops,2))

fst<-data.frame()
for (i in 1: nrow(comb)){
    pop1<-comb[i,1]
    pop2<-comb[i,2]
    df<-read.delim(paste0("../Data/new_vcf/angsd/fromVCF/2D/fst_folded_",pop1,"_",pop2,"_50kWindow_maf00"))
    conames<-colnames(df)[2:4]
    colnames(df)[4]<-"Fst"
    colnames(df)[1:3]<-conames
    df$pop<-paste0(pop1,".vs.",pop2)
    df$ch=as.integer(gsub("chr","", df$chr))
    df<-df[order(df$ch),]
    df$loc<-1:nrow(df)
    fst<-rbind(fst, df)
}

#Plot Fst values across Genome
fst$color<-"col1"
fst$color[fst$chr %in% evens]<-"col2"
fst$pop<-factor(fst$pop, levels=unique(fst$pop))

ggplot(fst, aes(x=loc, y=Fst, color=color))+
    facet_wrap(~pop, ncol = 1, strip.position="right")+
    geom_point(size=0.2, alpha=0.6)+
    scale_color_manual(values=c("gray60","steelblue"))+
    theme_bw()+
    ylab("Fst")+xlab('Genome position')+
    theme(legend.position = "none", panel.grid.major.x = element_blank(), panel.grid.minor.x = element_blank())+ggtitle("2006/07")+
    scale_x_continuous(breaks=rows$middle, labels=1:26)
ggsave("../Output/SFS/Y2006_Fst_pairwise_comparison.png", width = 16, height = 7, dpi=300)


compare<-unique(fst$pop)
pairfst<-data.frame(matrix(ncol=3, nrow=3), row.names=c("TB06","PWS07","SS06"))
colnames(pairfst)<-c("TB06","PWS07","SS06")
for (i in 1:3){
    pop1<-comb[i,1]
    pop2<-comb[i,2]
    df<-fst[fst$pop==compare[i],]
    pairfst[pop1,pop2]<-mean(df$Fst, na.rm=T)
    pairfst[pop2,pop1]<-mean(df$Fst, na.rm=T)
}
write.csv(pairfst,"../Output/SFS/Y2006_pairwiseFst_matrix.csv")

df<-pairfst
diag(df)<-0
df[lower.tri(df)]<-NA
df$pop<-rownames(df)
dfm<-melt(df,na.rm=T, id.vars='pop')
#NA to diagonal
dfm$value[dfm$value==0]<-NA
dfm$pop<-factor(dfm$pop, levels=c("TB06","PWS07","SS06"))
dfm$value<-round(dfm$value, 4)
ggplot(data = dfm, aes(pop, variable, fill = value))+
    geom_tile(color = "white")+
    scale_fill_gradientn(colors=c("white", "#0C54FFCC"), limits=c(0, (max(dfm$value, na.rm=T)+0.05)),na.value="gray80", 
                         name="Fst")+
    theme_minimal()+ xlab("")+ylab("")+
    theme(axis.text.x = element_text(angle = 0, vjust = 0, 
                                     size = 12, hjust = 0.5))+
    theme(axis.text.y = element_text(size = 12))+
    coord_fixed()+ggtitle("2006/07")+
    geom_text(aes(pop, variable, label = value), color = "black", size = 5)
ggsave(paste0("../Output/SFS/Y2006_pairwiseFst.png"), width = 5, height = 5, dpi=300)


#2017




f17<-read.csv("../Output/SFS/Fst_matrix_2017_all.csv")
f17<-f17[1:3,1:4]
# Melt the correlation matrix
f17m <- melt(f17, na.rm = TRUE)
f17m[f17m==0]<-NA

colnames(f17m)[1:3]<-c("P1","P2","fst")
f17m$P1<-factor(f17m$P1, levels=c("TB17","PWS17","SS17"))

ggplot(f17m, aes(P1, P2, fill = fst))+
    geom_tile(color = "white")+
    scale_fill_gradientn(colors=c("white", "#0C54FFCC"), limits=c(0, (max(f17m$fst, na.rm=T)+0.05)),na.value="gray80",  name="Fst")+
                        
    theme_minimal()+ xlab("")+ylab("")+
    theme(axis.text.x = element_text(angle = 0, vjust = 0, 
                                     size = 12, hjust = 0.5))+
    theme(axis.text.y = element_text(size = 12))+
    coord_fixed()+
    geom_text(aes(P1, P2, label = fst),  size = 5)
ggsave("../Output/SFS/Y2017_pairwiseFst.png", height = 5, width = 5, dpi=150)

# 3. Y1991 

df<-read.delim(paste0("../Data/new_vcf/angsd/fromVCF/2D/fst_folded_PWS91_TB91_50kWindow_maf00"))
conames<-colnames(df)[2:4]
colnames(df)[4]<-"Fst"
colnames(df)[1:3]<-conames
df$pop<-paste0("PWS91.vs.TB91")
df$ch=as.integer(gsub("chr","", df$chr))
df<-df[order(df$ch),]
df$loc<-1:nrow(df)
fst<-df
#Plot Fst values across Genome
fst$color<-"col1"
fst$color[fst$chr %in% evens]<-"col2"
fst$pop<-factor(fst$pop, levels=unique(fst$pop))

ggplot(fst, aes(x=loc, y=Fst, color=color))+
    facet_wrap(~pop, ncol = 1, strip.position="right")+
    geom_point(size=0.2, alpha=0.6)+
    scale_color_manual(values=c("gray60","steelblue"))+
    theme_bw()+
    ylab("Fst")+xlab('Genome position')+
    theme(legend.position = "none", panel.grid.major.x = element_blank(), panel.grid.minor.x = element_blank())+ggtitle("1991")+
    scale_x_continuous(breaks=rows$middle, labels=1:26)+
    annotate("text", x=1, y=0.7, label="Mean Fst = 0.142", hjust=0)
    
ggsave("../Output/SFS/Y1991_Fst_pairwise_comparison.png", width = 16, height = 2.5, dpi=300)

pairfst<-mean(fst$Fst, na.rm=T)

pairfst
#0.1417637

LS0tCnRpdGxlOiAiU0ZTIgpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgICAgdG9jOiB0cnVlIAogICAgICB0b2NfZmxvYXQ6IHRydWUKICAgICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICAgIHRoZW1lOiBsdW1lbgogICAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgICBkZl9wcmludDogcGFnZWQKCi0tLQpgYGB7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQp0b2MgPSB0YWJsZSBvZiBjb250ZW50cwoKYGBgCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBldmFsPUZBTFNFfQpzb3VyY2UoIi4uL1JzY3JpcHRzL0Jhc2VTY3JpcHRzLlIiKQpsaWJyYXJ5KGNvd3Bsb3QpCmxpYnJhcnkoUkNvbG9yQnJld2VyKQpgYGAKCgojIEVzdGlhbXRlIFNGUyB3aXRoIGFsbCBpbmRpdmlkdWFscyBhbmQgYWxsIHNpdGVzCgooZXN0aW1hdGVkIGJ5IGVhY2ggY2hyb21vc29tZSBhbmQgY29tYmluZSB0aGVtIGxhdGVyKSAoNS4yNi4yMn4pICAKClN0ZXAgMTogUnVuIFBXUzA3X3Nmc19zdGVwMS5zaCAoaW4gIi9EYXRhL1NsdXJ1bXNjcmlwdHMvU0ZTX2Zyb21CYW0vUFdTMDdfc2ZzX3N0ZXAxLnNoIikgZm9yIGVhY2ggcG9wdWxhdGlvbiAodGFrZXMgYSBsb25nIHRpbWUgdG8gY3JlYXRlIGEgc2FmIGZpbGUpICAKPGJyPgoKU3RlcCAyOiBSdW4gUFdTMDdfc2ZzX3N0ZXAyLnNoIHRvIGNyZWF0ZSB1bmZvbGRlZCBzZnMgZm9yIGVhY2ggY2hyb21vc29tZSAoQ2FuJ3QgcnVuIHRoZSB3aG9sZSBnZW5vbWUgZHVlIHRvIG1lbW9yeSBjb25zdHJhaW50cykgIAo8YnI+IAoKU3RlcCAyLjI6IFJ1biBQV1MwN19zZnNfc3RlcDJfZm9sZGVkLnNoIHRvIGNyZWF0ZSBmb2xkZWQgc2ZzIGZvciBlYWNoIGNocm9tb3NvbWUgICAKPGJyPgoKU3RlcCAzOiBSdW4gUiBzY3JpcHRzIHRvIGNvbWJpbmUgYWxsIHNmcyBpbnRvIDEKCmBgYHtiYXNoIGV2YWw9RkFMU0UsbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBhdCBGQVJNLCBydW4gdGhlIGZvbGxvd2luZyBzY3JpcHRzIHRvIGNvbWJpbmUgc2ZzIGZpbGVzCm1vZHVsZSBsb2FkIFIKUgpzb3VyY2UoImNvbWJpbmVTRlNmb2xkLlIiKSAKc291cmNlKCJjb21iaW5lU0ZTdW5mb2xkLlIiKSAKY29tYmluZVNGU3VuZm9sZCgiUFdTMDciKSAgICMgdGhpcyB3aWxsIGNyZWF0ZSBhICJQV1MwN191bmZvbGRlZC5zZnMiIGluIC9ob21lL2t0aXN0L3BoL2RhdGEvYW5nc2QvU0ZTL2Zyb21CYW0vCmNvbWJpbmVTRlNmb2xkKCJQV1MwNyIpICAgIyB0aGlzIHdpbGwgY3JlYXRlIGEgIlBXUzA3X2ZvbGRlZC5zZnMiIGluIC9ob21lL2t0aXN0L3BoL2RhdGEvYW5nc2QvU0ZTL2Zyb21CYW0vZm9sZGVkLwoKI0V4aXQgUiBieSB0eXBpbmcgCnF1aXQoKQpgYGAKCiAgICAKTG9jYWxseSwgeW91IGNhbiBydW4gaGVyZToKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KY29tYmluZVNGU2ZvbGQ8LWZ1bmN0aW9uKHBvcCl7CiAgICBjaDE8LXNjYW4ocGFzdGUwKCJEYXRhL25ld192Y2YvYW5nc2QvZnJvbUJhbS9mb2xkZWQvIixwb3AsIl9mb2xkZWRfY2hyMS5zZnMiKSkKICAgIHB3cy5zZnM8LWRhdGEuZnJhbWUoY2hyMT1jaDEpCiAgICBmb3IgKGkgaW4gMjoyNil7CiAgICAgICAgdmVjPC1zY2FuKHBhc3RlMCgiRGF0YS9uZXdfdmNmL2FuZ3NkL2Zyb21CYW0vZm9sZGVkLyIscG9wLCJfZm9sZGVkX2NociIsaSwiLnNmcyIpKQogICAgICAgIHB3cy5zZnNbLHBhc3RlMCgiY2hyIixpKV08LXZlYwogICAgfQogICAgcHdzLnNmcyRzdW08LXJvd1N1bXMocHdzLnNmcykKICAgIHNpbmsocGFzdGUwKCJEYXRhL25ld192Y2YvYW5nc2QvZnJvbUJhbS9mb2xkZWQvIixwb3AsIl9mb2xkZWQuc2ZzIikpCiAgICBjYXQocHdzLnNmcyRzdW0pCiAgICBzaW5rKE5VTEwpCn0KCmNvbWJpbmVTRlN1bmZvbGQ8LWZ1bmN0aW9uKHBvcCl7CiAgICBjaDE8LXNjYW4ocGFzdGUwKCJEYXRhL25ld192Y2YvYW5nc2QvZnJvbUJhbS91bmZvbGRlZC8iLHBvcCwiX3VuZm9sZGVkX2NocjEuc2ZzIikpCiAgICBwd3Muc2ZzPC1kYXRhLmZyYW1lKGNocjE9Y2gxKQogICAgZm9yIChpIGluIDI6MjYpewogICAgICAgIHZlYzwtc2NhbihwYXN0ZTAoIkRhdGEvbmV3X3ZjZi9hbmdzZC9mcm9tQmFtL3VuZm9sZGVkLyIscG9wLCJfdW5mb2xkZWRfY2hyIixpLCIuc2ZzIikpCiAgICAgICAgcHdzLnNmc1sscGFzdGUwKCJjaHIiLGkpXTwtdmVjCiAgICB9CiAgICBwd3Muc2ZzJHN1bTwtcm93U3Vtcyhwd3Muc2ZzKQogICAgc2luayhwYXN0ZTAoIkRhdGEvbmV3X3ZjZi9hbmdzZC9mcm9tQmFtL3VuZm9sZGVkLyIscG9wLCJfdW5mb2xkZWQuc2ZzIikpCiAgICBjYXQocHdzLnNmcyRzdW0pCiAgICBzaW5rKE5VTEwpCn0KCiNSdW4gd2l0aCB0aGUgJ3BvcCcgaWRlbnRpZmllcgpjb21iaW5lU0ZTdW5mb2xkKCJQV1MwNyIpCmNvbWJpbmVTRlNmb2xkKCJQV1MwNyIpCgpgYGAKClN0ZXAgNDogUnVuIFBXUzA3X3Nmc190aGV0YS5zaCB0byBjYWxjdWxhdGUgdGhldGEgYW5kIFRhamltYSdzIEQgZm9yIHVuZm9sZGVkLnNmcyAoRmF5ICYgV3UncyBIIHNob3VsZCBiZSB1c2VkIHdpdGggdW5mb2xkZWQgc2ZzKSAgCgpTdGVwIDQuMjogUnVuIFBXUzA3X3Nmc19zdGVwM19mb2xkZWQuc2ggdG8gY2FsY3VsYXRlIHRoZXRhIGFuZCBUYWppbWEncyBEIGZvciBmb2xkZWQuc2ZzIChUYWppbWEncyBEIHNob3VsZCBiZSB1c2VkIHdpdGggZm9sZGVkIHNmcykgIAoKIyMgU0ZTIGZyb20gYmFtIGZpbGVzIHsudGFic2V0fQoKIyMjIDFEU0ZTIFBXUwoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCnNvdXJjZSgiLi4vUnNjcmlwdHMvQmFzZVNjcmlwdHMuUiIpCnBvcHM8LWMoIlBXUzkxIiwiUFdTOTYiLCJQV1MwNyIsIlBXUzE3IikKCnNmczFEPC1kYXRhLmZyYW1lKCkKZm9yIChpIGluIDE6bGVuZ3RoKHBvcHMpKXsKICAgIHNmcyA8LSBzY2FuKHBhc3RlMCgiLi4vRGF0YS9uZXdfdmNmL2FuZ3NkL2Zyb21CYW0vY29tYmluZWQvIixwb3BzW2ldLCJfdW5mb2xkZWQuc2ZzIikpCiAgICBzZnMxIDwtIGRhdGEuZnJhbWUoYWM9c2ZzKQogICAgc2ZzMSRjb3VudDwtMDoobnJvdyhzZnMxKS0xKQogICAgI3JlbW92ZSB0aGUgaW52YXJpYWJsZSBzaXRlcwogICAgc2ZzMTwtc2ZzMVstYygxLG5yb3coc2ZzMSkpLF0KICAgIHNmczEkcG9wPC1wb3BzW2ldCiAgICBzZnMxRDwtcmJpbmQoc2ZzMUQsIHNmczEpCn0KICAgIApzZnMxRCRwb3A8LWZhY3RvcihzZnMxRCRwb3AsIGxldmVscz1wb3BzKQpnZ3Bsb3QoZGF0YT1zZnMxRCwgYWVzKHg9Y291bnQsIHk9YWMpKSsKICAgIGZhY2V0X3dyYXAofnBvcCwgbmNvbD00KSsKICAgICAgICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIGNvbG9yPSJncmF5IikreGxhYigiRnJlcXVlbmN5IGJpbiIpKyB5bGFiKCJOdW1iZXIgb2YgYWxsZWxlcyIpKwogICAgICAgIHRoZW1lX2NsYXNzaWMoKSsKICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPXNjYWxlczo6Y29tbWEpKwogICAgICAgIHRoZW1lKHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoCiAgICAgICAgICAgIGNvbG9yPSJibGFjayIsIGZpbGw9ImdyYXk4MCIsIHNpemU9MC41LCBsaW5ldHlwZT0ic29saWQiKSkKZ2dzYXZlKCIuLi9PdXRwdXQvU0ZTLzFEU0ZTX2Zyb21CYW1fUFdTLnBuZyIsIHdpZHRoID0gMTEsIGhlaWdodCA9IDIuMiwgZHBpPTMwMCkKYGBgCiFbXSguLi9PdXRwdXQvU0ZTLzFEU0ZTX2Zyb21CYW1fUFdTLnBuZykKCiMjIyBQaSAoz4ApCgpgYGB7ciBldmFsPUZBTFNFLG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGNsYXNzLnNvdXJjZSA9ICdmb2xkLXNob3cnfQpwb3BzPC1jKCJQV1M5MSIsIlBXUzk2IiwiUFdTMDciLCJQV1MxNyIpCnRoZXRhPC1kYXRhLmZyYW1lKCkKZm9yIChpIGluIDE6bGVuZ3RoKHBvcHMpKXsKICAgIHRoZXRhMjwtcmVhZC5kZWxpbShwYXN0ZTAoJy4uL0RhdGEvbmV3X3ZjZi9hbmdzZC9mcm9tQmFtL3VuZm9sZGVkLycscG9wc1tpXSwnXzUwa3dpbl8xMGtzdGVwLnBlc3RQRycpKQogICAgdGhldGEyJHBpPC10aGV0YTIkdFAvdGhldGEyJG5TaXRlcwogICAgZGY8LXRoZXRhMlssYygiQ2hyIiwiV2luQ2VudGVyIiwicGkiLCJmYXloIiApXQogICAgZGYkcG9wPC1wb3BzW2ldICAgIAogICAgdGhldGE8LXJiaW5kKHRoZXRhLCBkZikKfQoKI21lYW4gcGkgYW5kIEZheSdzIEggIChmcm9tIHVuZm9sZGVkIFNGUykKdGhldGEkcG9wPC1mYWN0b3IodGhldGEkcG9wLCBsZXZlbHM9cG9wcykKCmdncGxvdCh0aGV0YSwgYWVzKHg9cG9wLCB5PXBpKSkrCiAgICBnZW9tX2JveHBsb3QocG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpLCBjb2xvcj1ibHUsIG91dGxpZXIuYWxwaGEgPSAwLjYsb3V0bGllci5zaXplID0gMC43LHdpZHRoPTAuNikrCiAgICBnZW9tX3BvaW50KHN0YXQgPSAic3VtbWFyeSIsIGZ1biA9ICJtZWFuIixwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCkpKwogICAgeWxhYihleHByZXNzaW9uKHBpKSkreGxhYigiIikrCiAgICB0aGVtZV9idygpKwogICAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpKSsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoMS41LDIuNSwzLjUpLCBjb2xvcj0iZ3JheSIsIHNpemU9MC41KQpnZ3NhdmUoIi4uL091dHB1dC9TRlMvUGlfZXN0aW1hdGVzX1BXU19mcm9tQmFtLnBuZyIsIHdpZHRoID0gNSwgaGVpZ2h0ID0gMy41KQpgYGAKCiFbXSguLi9PdXRwdXQvU0ZTL1BpX2VzdGltYXRlc19QV1NfZnJvbUJhbS5wbmcpe3dpZHRoPTUwJX0gIAoKIyMjIEZheSdzIEgKCmBgYHtyIGV2YWw9RkFMU0UsbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgY2xhc3Muc291cmNlID0gJ2ZvbGQtc2hvdyd9CmdncGxvdCh0aGV0YSwgYWVzKHg9cG9wLCB5PWZheWgpKSsKICAgIGdlb21fYm94cGxvdChwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCksIGNvbG9yPWdyYiwgb3V0bGllci5hbHBoYSA9IDAuNixvdXRsaWVyLnNpemUgPSAwLjcsd2lkdGg9MC42KSsKICAgIGdlb21fcG9pbnQoc3RhdCA9ICJzdW1tYXJ5IiwgZnVuID0gIm1lYW4iLHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC44KSkrCiAgICB5bGFiKCJGYXkncyBIIikreGxhYigiIikrCiAgICB0aGVtZV9idygpKwogICAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpKSsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoMS41LDIuNSwzLjUpLCBjb2xvcj0iZ3JheSIsIHNpemU9MC41KQpnZ3NhdmUoIi4uL091dHB1dC9TRlMvRmF5SF9lc3RpbWF0ZXNfUFdTX2Zyb21CYW0ucG5nIiwgd2lkdGggPSA1LCBoZWlnaHQgPSAzLjUpCmBgYAohW10oLi4vT3V0cHV0L1NGUy9GYXlIX2VzdGltYXRlc19QV1NfZnJvbUJhbS5wbmcpe3dpZHRoPTUwJX0KCgoKIyMjIFRhamltYSdzIEQKCmBgYHtyIGV2YWw9RkFMU0UsbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgY2xhc3Muc291cmNlID0gJ2ZvbGQtc2hvdyd9CgojVGFqaW1hJ3MgRCAoZm9sZGVkIFNGUykKdGhldGE8LWRhdGEuZnJhbWUoKQpmb3IgKGkgaW4gMTpsZW5ndGgocG9wcykpewogICAgdGhldGEyPC1yZWFkLmRlbGltKHBhc3RlMCgnLi4vRGF0YS9uZXdfdmNmL2FuZ3NkL2Zyb21CYW0vZm9sZGVkLycscG9wc1tpXSwnXzUwa3dpbl8xMGtzdGVwLnBlc3RQRycpKQogICAgZGY8LXRoZXRhMlssYygiQ2hyIiwiV2luQ2VudGVyIiwiVGFqaW1hIiApXQogICAgZGYkcG9wPC1wb3BzW2ldICAgIAogICAgdGhldGE8LXJiaW5kKHRoZXRhLCBkZikKfQoKdGhldGEkcG9wPC1mYWN0b3IodGhldGEkcG9wLCBsZXZlbHM9cG9wcykKZ2dwbG90KHRoZXRhLCBhZXMoeD1wb3AsIHk9VGFqaW1hKSkrCiAgICBnZW9tX2JveHBsb3QocG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjgpLCBjb2xvcj1vcmcsIG91dGxpZXIuYWxwaGEgPSAwLjYsb3V0bGllci5zaXplID0gMC43LHdpZHRoPTAuNikrCiAgICBnZW9tX3BvaW50KHN0YXQgPSAic3VtbWFyeSIsIGZ1biA9ICJtZWFuIixwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuOCkpKwogICAgeWxhYigiVGFqaW1hJ3MgRCIpK3hsYWIoIiIpKwogICAgdGhlbWVfYncoKSsKICAgIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSkrCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKDEuNSwyLjUsMy41KSwgY29sb3I9ImdyYXkiLCBzaXplPTAuNSkKZ2dzYXZlKCIuLi9PdXRwdXQvU0ZTL1RhamltYURfUFdTX2Zyb21CYW0ucG5nIiwgd2lkdGggPSA1LCBoZWlnaHQgPSAzLjUpCgpgYGAKIVtdKC4uL091dHB1dC9TRlMvVGFqaW1hRF9QV1NfZnJvbUJhbS5wbmcpe3dpZHRoPTUwJX0KCiMjIEVzdGltYXRlIFNGUyBmcm9tIFZDRiBmaWxlcyAgIAooVXNpbmcgbWFmMC4wMCAtbm8gbG93IGFsbGVsZSBmcmVxIGN1dG9mZikKClN0ZXAgMTogUnVuIEJDMTdfYW5nc2RfU0ZTLnNoIChpbiAiL0RhdGEvU2x1cnVtc2NyaXB0cy9TRlNfZnJvbVZDRm1hZjAwLyIpIGZvciBlYWNoIHBvcHVsYXRpb24gLSB0aGlzIHdpbGwgY2FsY3VsYXRlIHNmcywgdGhldGEgZm9yIGJvdGggZm9sZGVkIGFuZCB1bmZvbGRlZCBTRlMuIAoKU3RlcCAyOiBDcmVhdGUgMkQgU0ZTIGJ5IHJ1bm5pbmcgZWFjaCBjb21iaW5hdGlvbiAoZXguIEJDMTdDQTE3MkRTRlMuc2ggaW4gIi9EYXRhL1NsdXJ1bXNjcmlwdHMvU0ZTX2Zyb21WQ0ZtYWYwMC8iKSAKClN0ZXAgMzogQ2FsY3VsYXRlIEZzdC9QYnMgZm9yIHBvcHVsYXRpb24gY29tYmluYXRpb25zIGJ5IHJ1bm5pbmcgM0RGc3Qgc2NyaXB0cyAoZXguIDNERnN0X3B3czEuc2gpIAoKYGBge3IgZXZhbD1GQUxTRSxtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojUGxvdCAyRCBTRlMgKFNmc19jb21wYXJpc29uLlIpCnNvdXJjZSgiLi4vUnNjcmlwdHMvQmFzZVNjcmlwdHMuUiIpCgojIyAyRCBTRlMKIyBUaGUgb3V0cHV0IGZyb20gQU5HU0QgaXMgYSBmbGF0dGVuIG1hdHJpeDogZWFjaCB2YWx1ZSBpcyB0aGUgY291bnQgb2Ygc2l0ZXMgd2l0aCB0aGUgY29ycmVzcG9uZGluZyBqb2ludCBmcmVxdWVuY3kgb3JkZXJlZCBhcwojIFswLDBdIFswLDFdIFswLDJdIC4uCgojIGZ1bmN0aW9uIHRvIGNyZWF0ZSBhIG1hdHJpeCBmcm9tIEFOR1NEIG91dHB1dCAoYSBmbGF0dGVuIG1hdHJpeCkKdmVjMm1hdDwtZnVuY3Rpb24odmVjLCBuMSxuMiwgcG9wMSwgcG9wMil7CiAgICBuMTwtbjEKICAgIG4yPC1uMgogICAgcG9wMTwtcG9wMQogICAgcG9wMjwtcG9wMgogICAgQU5HU0QuMkQuU0ZTIDwtIHNjYW4ocGFzdGUodmVjLCBzZXA9IiIpLCBxdWlldD1UKQogICAgQU5HU0QuMkQuU0ZTIDwtIHQobWF0cml4KEFOR1NELjJELlNGUywgbnJvdz1uMioyKzEsIG5jb2w9bjEqMisxKSkKICAgICMgbWFzayBub24tdmFyaWFudCBzaXRlcwogICAgQU5HU0QuMkQuU0ZTWzEsMV0gPC0gMAogICAgQU5HU0QuMkQuU0ZTW25yb3coQU5HU0QuMkQuU0ZTKSxuY29sKEFOR1NELjJELlNGUyldIDwtIDAKICAgIGRmPC1kYXRhLmZyYW1lKEFOR1NELjJELlNGUykKICAgIGNvbG5hbWVzKGRmKTwtMDoobmNvbChkZiktMSkKICAgIGRmJGNvdW50PC0wOihucm93KGRmKS0xKQogICAgcmV0dXJuKGRmKQp9CgojUGxvdCAyRCBTRlMgaGVhdG1hcCAgICAgCnBvcHMuaW5mbzwtcmVhZC5jc3YoIi4uL0RhdGEvU2FtcGxlX21ldGFkYXRhXzg5MnBvcHMuY3N2IikKcG9wcy5pbmZvJHlyPC0nJwpwb3BzLmluZm8keXJbcG9wcy5pbmZvJHllYXI9PTk2fHBvcHMuaW5mbyR5ZWFyPT05MV08LXBhc3RlMCgxOSxwb3BzLmluZm8keWVhcltwb3BzLmluZm8keWVhcj09OTZ8cG9wcy5pbmZvJHllYXI9PTkxXSkKcG9wcy5pbmZvJHlyW3BvcHMuaW5mbyR5ZWFyPT0wN3xwb3BzLmluZm8keWVhcj09MDZ8cG9wcy5pbmZvJHllYXI9PTE3XTwtcGFzdGUwKDIwLHBvcHMuaW5mbyR5ZWFyW3BvcHMuaW5mbyR5ZWFyPT0wN3xwb3BzLmluZm8keWVhcj09MDZ8cG9wcy5pbmZvJHllYXI9PTE3XSkKcG9wcy5pbmZvJHlyPC1hcHBseShwb3BzLmluZm9bInlyIl0sIDEsIGZ1bmN0aW9uKHgpIHtpZih4PT0yMDYpIHg9MjAwNgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHg9PTIwNykgeD0yMDA3CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbHNlIHg9eH0pCnBvcHMuaW5mbyR5cjwtYXMuaW50ZWdlcihwb3BzLmluZm8keXIpCnBvcHM8LXVuaXF1ZShwb3BzLmluZm8kUG9wdWxhdGlvbi5ZZWFyKQoKcHdzczwtYygiUFdTOTEiLCJQV1M5NiIsIlBXUzA3IiwiUFdTMTciKQp0YnM8LWMoIlRCOTEiLCJUQjk2IiwiVEIwNiIsIlRCMTciKQpzc3M8LWMoIlNTOTYiLCJTUzA2IiwiU1MxNyIpCnkxNzwtcG9wc1tncmVwKCIxNyIscG9wcyldCmNvbWIxPC1jb21ibihwd3NzLCAyKQpjb21iMTwtdChjb21iMSkKY29tYjI8LWNvbWJuKHRicywgMikKY29tYjI8LXQoY29tYjIpCmNvbWIzPC1jb21ibihzc3MsIDIpCmNvbWIzPC10KGNvbWIzKQpjb21iNDwtY29tYm4oeTE3LCAyKQpjb21iNDwtdChjb21iNCkKCiNodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy80OTY4OTA2OS9oZWF0bWFwLXdpdGgtY29udGludW91cy1yYWluYm93LWNvbG91cnMKY29scyA8LSByZXYocmFpbmJvdyg3KVstN10pICNyYWluYm93IGNvbG9ycyBmb3IgaGVhdG1hcAoKI1BXUwpQbG90czwtbGlzdCgpCnNmcy5wd3M8LWRhdGEuZnJhbWUoKQpmb3IgKGkgaW4gMTogbnJvdyhjb21iMSkpewogICAgcG9wMTwtY29tYjFbaSwxXQogICAgcG9wMjwtY29tYjFbaSwyXQogICAgbjE8LW5yb3cocG9wcy5pbmZvW3BvcHMuaW5mbyRQb3B1bGF0aW9uLlllYXI9PXBvcDEsXSkKICAgIG4yPC1ucm93KHBvcHMuaW5mb1twb3BzLmluZm8kUG9wdWxhdGlvbi5ZZWFyPT1wb3AyLF0pCiAgICAKICAgIHNmczE8LXZlYzJtYXQocGFzdGUwKCIuLi9EYXRhL25ld192Y2YvYW5nc2QvZnJvbVZDRi8yRC9mb2xkZWRfIixwb3AxLCJfIixwb3AyLCJfbWFmMDAuc2ZzIiksIG4xPW4xLCBuMj1uMiwgcG9wMT1wb3AxLCBwb3AyPXBvcDIpCiAgICAKICAgIGlmIChwb3BzLmluZm8keXJbcG9wcy5pbmZvJFBvcHVsYXRpb24uWWVhcj09cG9wMV1bMV0+cG9wcy5pbmZvJHlyW3BvcHMuaW5mbyRQb3B1bGF0aW9uLlllYXI9PXBvcDJdWzFdKXsKICAgICAgICBzZnMxPC1kYXRhLmZyYW1lKHQoc2ZzMVssMToobmNvbChzZnMxKS0xKV0pKQogICAgICAgIGNvbG5hbWVzKHNmczEpPC0wOihuY29sKHNmczEpLTEpCiAgICAgICAgc2ZzMSRjb3VudDwtMDoobnJvdyhzZnMxKS0xKQogICAgICAgIHAyPC1wb3AyCiAgICAgICAgcG9wMjwtcG9wMQogICAgICAgIHBvcDE8LXAyCiAgICB9CiAgICAjUGxvdCBmaXJzdCAzMAogICAgc2ZzMjwtc2ZzMVsxOjMwLDE6MzBdCiAgICBzZnMyJGNvdW50PC0wOihucm93KHNmczIpLTEpCiAgICBzZnNtMjwtbWVsdChzZnMyLCBpZC52YXJzPSJjb3VudCIpCiAgICBzZnNtMiR2YXJpYWJsZTwtYXMuaW50ZWdlcihhcy5jaGFyYWN0ZXIoc2ZzbTIkdmFyaWFibGUpKQogICAgCiAgICAjemVybyBhcyB3aGl0ZSAocmVwbGFjZSB3aXRoIE5BKQogICAgc2ZzbTIkdmFsdWVbc2ZzbTIkdmFsdWU9PTBdPC1OQQogICAgc2ZzbTIkcG9wMTwtcG9wMQogICAgc2ZzbTIkcG9wMjwtcG9wMgogICAgc2ZzLnB3czwtcmJpbmQoc2ZzLnB3cywgc2ZzbTIpCn0KCnNmcy5wd3MkcG9wMTwtZmFjdG9yKHNmcy5wd3MkcG9wMSwgbGV2ZWxzPWMoIlBXUzkxIiwiUFdTOTYiLCJQV1MwNyIsIlBXUzE3IikpCnNmcy5wd3MkcG9wMjwtZmFjdG9yKHNmcy5wd3MkcG9wMiwgbGV2ZWxzPWMoIlBXUzkxIiwiUFdTOTYiLCJQV1MwNyIsIlBXUzE3IikpCgpnZ3Bsb3Qoc2ZzLnB3cywgYWVzKHg9Y291bnQsIHk9dmFyaWFibGUpKSsKICAgIGZhY2V0X2dyaWQocG9wMn5wb3AxKSsKICAgIGdlb21fcmFzdGVyKGFlcyhmaWxsPWxvZzEwKHZhbHVlKSkpK3hsYWIoJycpK3lsYWIoIiIpKwogICAgc2NhbGVfZmlsbF9ncmFkaWVudG4oY29sb3JzPWNvbHMsIG5hbWU9ImxvZygjIG9mIGFsbGVsZXMpIiwgbmEudmFsdWUgPSAid2hpdGUiKSsKICAgIHRoZW1lX21pbmltYWwoKQpnZ3NhdmUoIi4uL091dHB1dC9TRlMvc2ZzXzJEX1BXUy5wbmciLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA4LCBkcGk9MzAwKQogICAKCiNUQgpzZnMudGI8LWRhdGEuZnJhbWUoKQpmb3IgKGkgaW4gMTogbnJvdyhjb21iMikpewogICAgcG9wMTwtY29tYjJbaSwxXQogICAgcG9wMjwtY29tYjJbaSwyXQogICAgbjE8LW5yb3cocG9wcy5pbmZvW3BvcHMuaW5mbyRQb3B1bGF0aW9uLlllYXI9PXBvcDEsXSkKICAgIG4yPC1ucm93KHBvcHMuaW5mb1twb3BzLmluZm8kUG9wdWxhdGlvbi5ZZWFyPT1wb3AyLF0pCiAgICAKICAgIHNmczE8LXZlYzJtYXQocGFzdGUwKCIuLi9EYXRhL25ld192Y2YvYW5nc2QvZnJvbVZDRi8yRC9mb2xkZWRfIixwb3AxLCJfIixwb3AyLCJfbWFmMDAuc2ZzIiksIG4xPW4xLCBuMj1uMiwgcG9wMT1wb3AxLCBwb3AyPXBvcDIpCiAgICAKICAgIGlmIChwb3BzLmluZm8keXJbcG9wcy5pbmZvJFBvcHVsYXRpb24uWWVhcj09cG9wMV1bMV0+cG9wcy5pbmZvJHlyW3BvcHMuaW5mbyRQb3B1bGF0aW9uLlllYXI9PXBvcDJdWzFdKXsKICAgICAgICBzZnMxPC1kYXRhLmZyYW1lKHQoc2ZzMVssMToobmNvbChzZnMxKS0xKV0pKQogICAgICAgIGNvbG5hbWVzKHNmczEpPC0wOihuY29sKHNmczEpLTEpCiAgICAgICAgc2ZzMSRjb3VudDwtMDoobnJvdyhzZnMxKS0xKQogICAgICAgIHAyPC1wb3AyCiAgICAgICAgcG9wMjwtcG9wMQogICAgICAgIHBvcDE8LXAyCiAgICB9CiAgICAjUGxvdCBmaXJzdCAzMAogICAgc2ZzMjwtc2ZzMVsxOjMwLDE6MzBdCiAgICBzZnMyJGNvdW50PC0wOihucm93KHNmczIpLTEpCiAgICBzZnNtMjwtbWVsdChzZnMyLCBpZC52YXJzPSJjb3VudCIpCiAgICBzZnNtMiR2YXJpYWJsZTwtYXMuaW50ZWdlcihhcy5jaGFyYWN0ZXIoc2ZzbTIkdmFyaWFibGUpKQogICAgCiAgICAjemVybyBhcyB3aGl0ZSAocmVwbGFjZSB3aXRoIE5BKQogICAgc2ZzbTIkdmFsdWVbc2ZzbTIkdmFsdWU9PTBdPC1OQQogICAgc2ZzbTIkcG9wMTwtcG9wMQogICAgc2ZzbTIkcG9wMjwtcG9wMgogICAgc2ZzLnRiPC1yYmluZChzZnMudGIsIHNmc20yKQp9CgpzZnMudGIkcG9wMTwtZmFjdG9yKHNmcy50YiRwb3AxLCBsZXZlbHM9YygiVEI5MSIsIlRCOTYiLCJUQjA2IiwiVEIxNyIpKQpzZnMudGIkcG9wMjwtZmFjdG9yKHNmcy50YiRwb3AyLCBsZXZlbHM9YygiVEI5MSIsIlRCOTYiLCJUQjA2IiwiVEIxNyIpKQoKZ2dwbG90KHNmcy50YiwgYWVzKHg9Y291bnQsIHk9dmFyaWFibGUpKSsKICAgIGZhY2V0X2dyaWQocG9wMn5wb3AxKSsKICAgIGdlb21fcmFzdGVyKGFlcyhmaWxsPWxvZzEwKHZhbHVlKSkpK3hsYWIoJycpK3lsYWIoIiIpKwogICAgc2NhbGVfZmlsbF9ncmFkaWVudG4oY29sb3JzPWNvbHMsIG5hbWU9ImxvZygjIG9mIGFsbGVsZXMpIiwgbmEudmFsdWUgPSAid2hpdGUiKSsKICAgIHRoZW1lX21pbmltYWwoKQpnZ3NhdmUoIi4uL091dHB1dC9TRlMvc2ZzXzJEX1RCLnBuZyIsIHdpZHRoID0gMTAsIGhlaWdodCA9IDgsIGRwaT0zMDApCgojU1MKc2ZzLnNzPC1kYXRhLmZyYW1lKCkKZm9yIChpIGluIDE6IG5yb3coY29tYjMpKXsKICAgIHBvcDE8LWNvbWIzW2ksMV0KICAgIHBvcDI8LWNvbWIzW2ksMl0KICAgIG4xPC1ucm93KHBvcHMuaW5mb1twb3BzLmluZm8kUG9wdWxhdGlvbi5ZZWFyPT1wb3AxLF0pCiAgICBuMjwtbnJvdyhwb3BzLmluZm9bcG9wcy5pbmZvJFBvcHVsYXRpb24uWWVhcj09cG9wMixdKQogICAgc2ZzMTwtdmVjMm1hdChwYXN0ZTAoIi4uL0RhdGEvbmV3X3ZjZi9hbmdzZC9mcm9tVkNGLzJEL2ZvbGRlZF8iLHBvcDEsIl8iLHBvcDIsIl9tYWYwMC5zZnMiKSwgbjE9bjEsIG4yPW4yLCBwb3AxPXBvcDEsIHBvcDI9cG9wMikKICAgIGlmIChwb3BzLmluZm8keXJbcG9wcy5pbmZvJFBvcHVsYXRpb24uWWVhcj09cG9wMV1bMV0+cG9wcy5pbmZvJHlyW3BvcHMuaW5mbyRQb3B1bGF0aW9uLlllYXI9PXBvcDJdWzFdKXsKICAgICAgICBzZnMxPC1kYXRhLmZyYW1lKHQoc2ZzMVssMToobmNvbChzZnMxKS0xKV0pKQogICAgICAgIGNvbG5hbWVzKHNmczEpPC0wOihuY29sKHNmczEpLTEpCiAgICAgICAgc2ZzMSRjb3VudDwtMDoobnJvdyhzZnMxKS0xKQogICAgICAgIHAyPC1wb3AyCiAgICAgICAgcG9wMjwtcG9wMQogICAgICAgIHBvcDE8LXAyCiAgICB9CiAgICAjUGxvdCBmaXJzdCAzMAogICAgc2ZzMjwtc2ZzMVsxOjMwLDE6MzBdCiAgICBzZnMyJGNvdW50PC0wOihucm93KHNmczIpLTEpCiAgICBzZnNtMjwtbWVsdChzZnMyLCBpZC52YXJzPSJjb3VudCIpCiAgICBzZnNtMiR2YXJpYWJsZTwtYXMuaW50ZWdlcihhcy5jaGFyYWN0ZXIoc2ZzbTIkdmFyaWFibGUpKQogICAgCiAgICAjemVybyBhcyB3aGl0ZSAocmVwbGFjZSB3aXRoIE5BKQogICAgc2ZzbTIkdmFsdWVbc2ZzbTIkdmFsdWU9PTBdPC1OQQogICAgc2ZzbTIkcG9wMTwtcG9wMQogICAgc2ZzbTIkcG9wMjwtcG9wMgogICAgc2ZzLnNzPC1yYmluZChzZnMuc3MsIHNmc20yKQp9CnNmcy5zcyRwb3AxPC1mYWN0b3Ioc2ZzLnNzJHBvcDEsIGxldmVscz1jKCJTUzk2IiwiU1MwNiIsIlNTMTciKSkKc2ZzLnNzJHBvcDI8LWZhY3RvcihzZnMuc3MkcG9wMiwgbGV2ZWxzPWMoIlNTOTYiLCJTUzA2IiwiU1MxNyIpKQoKZ2dwbG90KHNmcy5zcywgYWVzKHg9Y291bnQsIHk9dmFyaWFibGUpKSsKICAgIGZhY2V0X2dyaWQocG9wMn5wb3AxKSsKICAgIGdlb21fcmFzdGVyKGFlcyhmaWxsPWxvZyh2YWx1ZSkpKSt4bGFiKCcnKSt5bGFiKCIiKSsKICAgIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG9ycz1jb2xzLCBuYW1lPSJsb2coIyBvZiBhbGxlbGVzKSIsIG5hLnZhbHVlID0gIndoaXRlIikrCiAgICB0aGVtZV9taW5pbWFsKCkKZ2dzYXZlKCIuLi9PdXRwdXQvU0ZTL3Nmc18yRF9TUy5wbmciLCB3aWR0aCA9IDEwLCBoZWlnaHQgPSA4LCBkcGk9MzAwKQoKIzIwMTcgcG9wcwpzZnMxNzwtZGF0YS5mcmFtZSgpCmZvciAoaSBpbiAxOiBucm93KGNvbWI0KSl7CiAgICBwb3AxPC1jb21iNFtpLDFdCiAgICBwb3AyPC1jb21iNFtpLDJdCiAgICBuMTwtbnJvdyhwb3BzLmluZm9bcG9wcy5pbmZvJFBvcHVsYXRpb24uWWVhcj09cG9wMSxdKQogICAgbjI8LW5yb3cocG9wcy5pbmZvW3BvcHMuaW5mbyRQb3B1bGF0aW9uLlllYXI9PXBvcDIsXSkKICAgIHNmczE8LXZlYzJtYXQocGFzdGUwKCIuLi9EYXRhL25ld192Y2YvYW5nc2QvZnJvbVZDRi8yRC9mb2xkZWRfIixwb3AxLCJfIixwb3AyLCJfbWFmMDAuc2ZzIiksIG4xPW4xLCBuMj1uMiwgcG9wMT1wb3AxLCBwb3AyPXBvcDIpCiAgICAKICAgICNQbG90IGZpcnN0IDMwCiAgICBzZnMyPC1zZnMxWzE6MzAsMTozMF0KICAgIHNmczIkY291bnQ8LTA6KG5yb3coc2ZzMiktMSkKICAgIHNmc20yPC1tZWx0KHNmczIsIGlkLnZhcnM9ImNvdW50IikKICAgIHNmc20yJHZhcmlhYmxlPC1hcy5pbnRlZ2VyKGFzLmNoYXJhY3RlcihzZnNtMiR2YXJpYWJsZSkpCiAgICAKICAgICN6ZXJvIGFzIHdoaXRlIChyZXBsYWNlIHdpdGggTkEpCiAgICBzZnNtMiR2YWx1ZVtzZnNtMiR2YWx1ZT09MF08LU5BCiAgICBzZnNtMiRwb3AxPC1wb3AxCiAgICBzZnNtMiRwb3AyPC1wb3AyCiAgICBzZnMxNzwtcmJpbmQoc2ZzMTcsIHNmc20yKQp9CgpzZnMxNyRwb3AxPC1mYWN0b3Ioc2ZzMTckcG9wMSwgbGV2ZWxzPXBhc3RlKHkxNykpCnNmczE3JHBvcDI8LWZhY3RvcihzZnMxNyRwb3AyLCBsZXZlbHM9cGFzdGUoeTE3KSkKCmdncGxvdChzZnMxNywgYWVzKHg9Y291bnQsIHk9dmFyaWFibGUpKSsKICAgIGZhY2V0X2dyaWQocG9wMn5wb3AxKSsKICAgIGdlb21fcmFzdGVyKGFlcyhmaWxsPWxvZyh2YWx1ZSkpKSt4bGFiKCcnKSt5bGFiKCIiKSsKICAgIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG9ycz1jb2xzLCBuYW1lPSJsb2coIyBvZiBhbGxlbGVzKSIsIG5hLnZhbHVlID0gIndoaXRlIikrCiAgICB0aGVtZV9taW5pbWFsKCkKZ2dzYXZlKCIuLi9PdXRwdXQvU0ZTL3Nmc18yRF8yMDE3LnBuZyIsIHdpZHRoID0gMjAsIGhlaWdodCA9IDE2LCBkcGk9MzAwKQpgYGAKCiMjIyAxRCBTRlMgYWxsIHBvcHVsYXRpb25zIChEb3duc2FtcGxlZCBiYW0gZmlsZXMpICAKIVtdKC4uL091dHB1dC9TRlMvMURTRlNfYWxsX2Rvd25zYW1wbGVkLnBuZykgIAoKIyMjIDJEIFNGUyBQV1MgIAohW10oLi4vT3V0cHV0L1NGUy9zZnNfMkRfUFdTLnBuZyl7d2lkdGg9NTAlfQoKIyMjIDJEIFNGUyBUQiAgICAKIVtdKC4uL091dHB1dC9TRlMvc2ZzXzJEX1RCLnBuZyl7d2lkdGg9NTAlfQoKIyMjIDJEIFNGUyBTUyAgIAohW10oLi4vT3V0cHV0L1NGUy9zZnNfMkRfU1MucG5nKXt3aWR0aD01MCV9ICAKCiMjIyAyRCBTRlMgKDIwMTcpICAgICAKIVtdKC4uL091dHB1dC9TRlMvc2ZzXzJEXzIwMTcucG5nKXt3aWR0aD03MCV9ICAKCgojIEZzdCBiZXR3ZWVuIHllYXJzIHBlciBwb3B1bGF0aW9uIAoKIyMgUFdTICAKCiMjIyBGc3QgYWxvbmcgdGhlIGdlbm9tZQpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIyMgRnN0IGVzdGltYXRlcyBmcm9tIDJEc2ZzCnBvcHM8LWMoIlBXUzkxIiwiUFdTOTYiLCJQV1MwNyIsIlBXUzE3IikKY29tYjwtdChjb21ibihwb3BzLDIpKQoKZnN0PC1kYXRhLmZyYW1lKCkKZm9yIChpIGluIDE6IG5yb3coY29tYikpewogICAgcG9wMTwtY29tYltpLDFdCiAgICBwb3AyPC1jb21iW2ksMl0KICAgIGRmPC1yZWFkLmRlbGltKHBhc3RlMCgiLi4vRGF0YS9uZXdfdmNmL2FuZ3NkL2Zyb21WQ0YvMkQvZnN0XyIscG9wMSwiXyIscG9wMiwiXzUwa1dpbmRvd19tYWYwMCIpKQogICAgY29uYW1lczwtY29sbmFtZXMoZGYpWzI6NF0KICAgIGNvbG5hbWVzKGRmKVs0XTwtIkZzdCIKICAgIGNvbG5hbWVzKGRmKVsxOjNdPC1jb25hbWVzCiAgICBkZiRwb3A8LXBhc3RlMChwb3AxLCIudnMuIixwb3AyKQogICAgZGYkY2g9YXMuaW50ZWdlcihnc3ViKCJjaHIiLCIiLCBkZiRjaHIpKQogICAgZGY8LWRmW29yZGVyKGRmJGNoKSxdCiAgICBkZiRsb2M8LTE6bnJvdyhkZikKICAgIGZzdDwtcmJpbmQoZnN0LCBkZikKfQoKZXZlbnM8LXBhc3RlMCgiY2hyIixzZXEoMiwyNiwgYnk9MikpCiNQbG90IEZzdCB2YWx1ZXNlIGFjcm9zcyBHZW5vbWUKZnN0JGNvbG9yPC0iY29sMSIKZnN0JGNvbG9yW2ZzdCRjaHIgJWluJSBldmVuc108LSJjb2wyIgpmc3QkcG9wPC1mYWN0b3IoZnN0JHBvcCwgbGV2ZWxzPXVuaXF1ZShmc3QkcG9wKSkKCiNhZGQgY2hyb21vc29tZSBudW1iZXIKZGY8LWZzdFtmc3QkcG9wPT0iUFdTOTEudnMuUFdTOTYiLF0Kcm93czwtZGF0YS5mcmFtZShjaHI9MToyNikKZm9yIChpIGluIDE6MjYpewogICAgaWYgKGkgPT0xKXsKICAgICAgICByb3dzJG5baV08LW5yb3coZGZbZGYkY2g9PWksXSkKICAgICAgICByb3dzJG1pZGRsZVtpXTwtLW5yb3coZGZbZGYkY2g9PWksXSkvMgogICAgfQogICAgaWYgKGkgPjEpewogICAgICAgIHJvd3MkbltpXTwtbnJvdyhkZltkZiRjaD09aSxdKQogICAgICAgIHJvd3MkbWlkZGxlW2ldPC1zdW0ocm93cyRuWzE6KGktMSldKStyb3dzJG5baV0vMgogICAgfQp9CiMKZ2dwbG90KGZzdCwgYWVzKHg9bG9jLCB5PUZzdCwgY29sb3I9Y29sb3IpKSsKICAgIGZhY2V0X3dyYXAofnBvcCwgbmNvbCA9IDEsIHN0cmlwLnBvc2l0aW9uPSJyaWdodCIpKwogICAgZ2VvbV9wb2ludChzaXplPTAuMikrCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoImdyYXk1MCIsInN0ZWVsYmx1ZSIpKSsKICAgIHRoZW1lX2J3KCkrCiAgICB5bGFiKCJGc3QiKSt4bGFiKCdHZW5vbWUgcG9zaXRpb24nKSsKICAgIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgcGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpLCBwYW5lbC5ncmlkLm1pbm9yLnggPSBlbGVtZW50X2JsYW5rKCkpKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1yb3dzJG1pZGRsZSwgbGFiZWxzPTE6MjYpCmdnc2F2ZSgiLi4vT3V0cHV0L1NGUy9QV1NfRnN0X3BhaXJ3aXNlX2NvbXBhcmlzb24ucG5nIiwgd2lkdGggPSAyMCwgaGVpZ2h0ID0gMTAsIGRwaT0xNTApCmBgYAohW1BhaXJ3aXNlIEZzdCBhbG9uZyB0aGUgZ2Vub21lXSguLi9PdXRwdXQvU0ZTL1BXU19Gc3RfcGFpcndpc2VfY29tcGFyaXNvbi5wbmcpICAKIyMjIFBhaXJ3aXNlIEZzdCBhbG9uZyBlYWNoIGNocm9tb3NvbWUKCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMjIFBsb3QgRnN0IHZhbHVlcyBhbG9uZyBlYWNoIGNocm9tb3NvbWUKZnN0JGNocjwtZmFjdG9yKGZzdCRjaHIsIGxldmVscz1wYXN0ZTAoImNociIsMToyNikpCmZzdHB3PC1mc3QKcGxvdHM8LWxpc3QoKQpjb21wYXJlPC1wYXN0ZTAodW5pcXVlKGZzdHB3JHBvcCkpCm1heChmc3RwdyRGc3QpCmZvciAoaSBpbiAxOjYpeyAKICAgIGZzPC1nc3ViKCJ2cy4iLCIiLGNvbXBhcmVbaV0pCiAgICBwb3BzIDwtIHVubGlzdChzdHJzcGxpdChmcywgIlxcLiIpKQogICAgbWF4eTwtbWF4KGZzdHB3JEZzdFtmc3RwdyRwb3A9PWNvbXBhcmVbaV1dKQogICAgIyBGc3Qgd2l0aCBhY3R1YWwgbGluZSB0byBoaWdobGlnaHQgdGhlIGRpZmZlcmVuY2VzCiAgICBwbG90c1tbaV1dIDwtIGdncGxvdChmc3Rwd1tmc3RwdyRwb3A9PWNvbXBhcmVbaV0sXSwgYWVzKHggPW1pZFBvcywgeSA9RnN0ICkpICsgCiAgICAgICAgZ2VvbV9wb2ludChzaXplID0gMSwgY29sb3IgPSBncnksYWxwaGEgPSAwLjQsIHNoYXBlID0gMSkrCiAgICAgICAgdGhlbWVfbWluaW1hbCgpK3lsaW0oMCxtYXh5KzAuMDIpKwogICAgICAgIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSkrCiAgICAgICAgeWxhYigiRnN0XG4iKSsgeGxhYigiIikrIAogICAgICAgIGdndGl0bGUocGFzdGUwKHBvcHNbMV0sIiB2cy4iLCBwb3BzWzJdKSkrCiAgICAgICAgZ2VvbV9saW5lKGNvbG9yPWJsdSwgc2l6ZT0wLjIpKwogICAgICAgIGZhY2V0X3dyYXAofmNociwgbmNvbCA9IDkpCn0KI3NhdmUgdGhlIHBsb3RzIHRvZ2V0aGVyCntwbmcocGFzdGUwKCIuLi9PdXRwdXQvU0ZTL1BXU19Gc3RfbWFmMDBfY2hyLnBuZyIpLCBoZWlnaHQgPSA4LCB3aWR0aCA9IDE4LCByZXM9MTUwLCB1bml0cyA9ICJpbiIpCmdyaWQuYXJyYW5nZShwbG90c1tbM11dLCBwbG90c1tbMl1dLCBwbG90c1tbNF1dLCBwbG90c1tbMV1dLHBsb3RzW1s1XV0scGxvdHNbWzZdXSwgbmNvbD0zKQpkZXYub2ZmKCl9CmBgYAohW1BhaXJ3aXNlIEZzdCBmb3IgZWFjaCBnZW5vbWVdKC4uL091dHB1dC9TRlMvUFdTX0ZzdF9tYWYwMF9jaHIucG5nKSAgCiAgCgojIyMgQ3JlYXRlIHBhaXJ3aXNlIEZzdCBtYXRyaXggCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIyAuLmNvbnRpbnVlZCBmcm9tIGFib3ZlIApwb3BzPC1jKCJQV1M5MSIsIlBXUzk2IiwiUFdTMDciLCJQV1MxNyIpCmNvbWI8LXQoY29tYm4ocG9wcywyKSkKCiMjIFBsb3QgYXZlcmFnZSBmc3QgaW4gYSBoZWF0bWFwCmNvbXA8LXVuaXF1ZShmc3QkcG9wKQpwYWlyZnN0PC1kYXRhLmZyYW1lKG1hdHJpeChuY29sPTQsIG5yb3c9NCksIHJvdy5uYW1lcz1wb3BzKQpjb2xuYW1lcyhwYWlyZnN0KTwtcG9wcwpmb3IgKGkgaW4gMTo2KXsKICAgIHBvcDE8LWNvbWJbaSwxXQogICAgcG9wMjwtY29tYltpLDJdCiAgICBkZjwtZnN0W2ZzdCRwb3A9PWNvbXBbaV0sXQogICAgcGFpcmZzdFtwb3AxLHBvcDJdPC1tZWFuKGRmJEZzdCwgbmEucm09VCkKICAgICNwYWlyZnN0W3BvcDIscG9wMV08LW1lYW4oZGYkRnN0LCBuYS5ybT1UKQp9CndyaXRlLmNzdihwYWlyZnN0LCIuLi9PdXRwdXQvU0ZTL1BXU19wYWlyd2lzZUZzdF9tYXRyaXguY3N2IikKCnBhaXJmc3Q8LXJlYWQuY3N2KCIuLi9PdXRwdXQvU0ZTL1BXU19wYWlyd2lzZUZzdF9tYXRyaXguY3N2Iiwgcm93Lm5hbWVzID0gMSkKZGY8LXBhaXJmc3QKZGlhZyhkZik8LTAKZGYkcG9wPC1yb3duYW1lcyhkZikKZGZtPC1tZWx0KGRmLG5hLnJtPVQsIGlkLnZhcnM9J3BvcCcpCgojTkEgdG8gZGlhZ29uYWwKZGZtJHZhbHVlW2RmbSR2YWx1ZT09MF08LU5BCmRmbSRwb3A8LWZhY3RvcihkZm0kcG9wLCBsZXZlbHM9cG9wcykKZGZtJHZhbHVlPC1yb3VuZChkZm0kdmFsdWUsIDQpCmdncGxvdChkYXRhID0gZGZtLCBhZXMocG9wLCB2YXJpYWJsZSwgZmlsbCA9IHZhbHVlKSkrCiAgICBnZW9tX3RpbGUoY29sb3IgPSAid2hpdGUiKSsKICAgIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG9ycz1jKCJ3aGl0ZSIsICIjMEM1NEZGIiksIGxpbWl0cz1jKDAsIChtYXgoZGZtJHZhbHVlLCBuYS5ybT1UKSswLjAwNSkpLG5hLnZhbHVlPSJncmF5ODAiLCAKICAgICAgICAgICAgICAgICAgICAgICAgIG5hbWU9IkZzdCIpKwogICAgdGhlbWVfbWluaW1hbCgpKyB4bGFiKCIiKSt5bGFiKCIiKSsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgdmp1c3QgPSAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAxMiwgaGp1c3QgPSAwLjUpKSsKICAgIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikpKwogICAgY29vcmRfZml4ZWQoKSsKICAgIGdlb21fdGV4dChhZXMocG9wLCB2YXJpYWJsZSwgbGFiZWwgPSB2YWx1ZSksIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDUpCmdnc2F2ZShwYXN0ZTAoIi4uL091dHB1dC9TRlMvcGFpcndpc2VGc3RfUFdTLnBuZyIpLCB3aWR0aCA9IDUsIGhlaWdodCA9IDUsIGRwaT0xNTApCmBgYAohW1BXUyBQYWlyd2lzZSBGc3RdKC4uL091dHB1dC9TRlMvcGFpcndpc2VGc3RfUFdTLnBuZyl7d2lkdGg9NTAlfQoKIyMjIEZzdCBjaGFuZ2Ugb3ZlciB0aW1lICAKCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgUGxvdCBGc3QgaW4gYSBiYXIgcGxvdCBvcmRlcmVkIGFuZCBjb2xvcmVkIGluIHRoZSBzYW1lIHdheSBhcyBGc3QvUGkgc2h1ZmZsZSByZXN1bHRzIChTaHVmZmxpbmdfcGkuZnN0LnRlaGF0LlJtZCkKZnN0czwtZGZtWyFpcy5uYShkZm0kdmFsdWUpLF0KZnN0cyRjb21wPC1wYXN0ZTAoZnN0cyRwb3AsIl8iLGZzdHMkdmFyaWFibGUpCgojc2V0IHRoZSBjb2xvcnMKZGl2MTwtZGl2ZXJnaW5nX2hjbCg2LCBwYWxldHRlPSJCbHVlLVJlZCIpCmRpdjI8LXJldihkaXYxKQpuYW1lcyhkaXYyKTwtYygiUFdTOTZfUFdTMDciLCJQV1MwN19QV1MxNyIsIlBXUzkxX1BXUzk2IiwgIlBXUzkxX1BXUzA3IiwgIlBXUzkxX1BXUzE3IiwiUFdTOTZfUFdTMTciKQpmc3RzPC1mc3RzW29yZGVyKGZzdHMkdmFsdWUsIGRlY3JlYXNpbmcgPSBUKSxdCmZzdHMkY29tcDwtZmFjdG9yKGZzdHMkY29tcCwgbGV2ZWxzPXBhc3RlMCh1bmlxdWUoZnN0cyRjb21wKSkpCgpnZ3Bsb3QoZnN0cywgYWVzKHg9Y29tcCwgeT12YWx1ZSwgZmlsbD1jb21wKSkrCiAgICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpKwogICAgc2NhbGVfZmlsbF9tYW51YWwobmFtZSA9ICJjb21wIix2YWx1ZXMgPSBkaXYyKSsKICAgIHhsYWIoJycpK3lsYWIoJ0ZzdCcpKwogICAgdGhlbWVfY2xhc3NpYygpKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCmdnc2F2ZSgiLi4vT3V0cHV0L0ZzdC9QYWlyd2lzZUZzdF9vcmRlcmVkLnBuZyIsIHdpZHRoID0gNCwgaGVpZ2h0ID0gMi44LCBkcGk9MzAwICkKCiNGc3Qgb3ZlciB0aW1lCgpmc3RzMjwtZnN0c1tmc3RzJGNvbXAgJWluJSBjKCJQV1M5MV9QV1M5NiIsIlBXUzk2X1BXUzA3IiwiUFdTMDdfUFdTMTciKSxdCmZzdHMyJHRpbWU8LTEKZnN0czIkdGltZVtmc3RzMiRjb21wPT0iUFdTOTZfUFdTMDciXTwtMgpmc3RzMiR0aW1lW2ZzdHMyJGNvbXA9PSJQV1MwN19QV1MxNyJdPC0zCgpnZ3Bsb3QoZnN0czIsIGFlcyh4PXRpbWUsIHk9dmFsdWUpKSsKICAgIGdlb21fcG9pbnQoc2l6ZT0zLCBjb2xvcj0ic3RlZWxibHVlIikrCiAgICBnZW9tX3BhdGgoY29sb3I9InN0ZWVsYmx1ZSIpKwogICAgdGhlbWVfY2xhc3NpYygpK3lsYWIoIkZzdCIpK3hsYWIoIiIpKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDEsMiwzKSwgbGFiZWxzPWMoIjkxLTk2IiwgIjk2LTA3IiwiMDctMTciKSkKZ2dzYXZlKCIuLi9PdXRwdXQvRnN0L0ZzdF9vdmVyVGltZS5wbmciLCB3aWR0aCA9IDQsIGhlaWdodCA9IDIuOCwgZHBpPTMwMCApCgpmc3RzJHNlcmllczwtIjE5OTEtMjAwNywgMTk5MS0yMDE3Igpmc3RzJHNlcmllc1tmc3RzJGNvbXAgJWluJSBjKCJQV1M5MV9QV1M5NiIsIlBXUzk2X1BXUzA3IiwiUFdTMDdfUFdTMTciKV08LSIxOTkxLTE5OTYsIDE5OTYtMjAwNywgMjAwNy0yMDE3Igpmc3RzJHNlcmllc1tmc3RzJGNvbXAgPT0iUFdTOTZfUFdTMTciXTwtIjE5OTYtMjAxNyIKZnN0cyR0aW1lPC0xCmZzdHMkdGltZVtmc3RzJHZhcmlhYmxlPT0iUFdTMTciXTwtMwpmc3RzJHRpbWVbZnN0cyR2YXJpYWJsZT09IlBXUzA3Il08LTIKc291cmNlKCIuLi9Sc2NyaXB0cy9CYXNlU2NyaXB0cy5SIikKCmdncGxvdChmc3RzLCBhZXMoeD10aW1lLCB5PXZhbHVlLCBjb2xvcj1zZXJpZXMpKSsKICAgIGdlb21fcG9pbnQoc2l6ZT0zKSsKICAgIGdlb21fcGF0aCgpKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jb2xzKSsKICAgIHRoZW1lX2NsYXNzaWMoKSt5bGFiKCJGc3QiKSt4bGFiKCIiKSsKICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3M9YygxLDIsMyksIGxhYmVscz1jKCIxOTkxLTE5OTYiLCAifjIwMDciLCJ+MjAxNyIpKSsKICAgIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKZ2dzYXZlKCIuLi9PdXRwdXQvRnN0L0ZzdF9vdmVyVGltZV9hbGxDb21wYXJpc29uLnBuZyIsIHdpZHRoID0gNiwgaGVpZ2h0ID0gMi44LCBkcGk9MzAwICkKCgpmc3RQMTwtZnN0cwpmc3RQMjwtZnN0czIKYGBgCgohW10oLi4vT3V0cHV0L0ZzdC9Gc3Rfb3ZlclRpbWVfUFdTX2FsbENvbXBhcmlzb24ucG5nKSAgCgoKCiMjIyBQbG90IG1lYW4gRnN0IGZvciBlYWNoIGNocm9tb3NvbWUgIAoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBQbG90IG1lYW4gRnN0IG9mIGVhY2ggY2hyb21vc21lCkZzdDwtZGF0YS5mcmFtZSgpCmNvbXBhcmU8LXBhc3RlMCh1bmlxdWUoZnN0cHckcG9wKSkKZm9yIChqIGluIDE6MjYpewogICAgZnN0LmNoPC1mc3RbZnN0JGNoPT1qLF0KICAgIHBhaXJjaDwtZGF0YS5mcmFtZShtYXRyaXgobmNvbD00LCBucm93PTQpLCByb3cubmFtZXM9cG9wcykKICAgIGNvbG5hbWVzKHBhaXJjaCk8LXBvcHMKICAgIGZvciAoaSBpbiAxOjYpewogICAgICAgIHBvcDE8LWNvbWJbaSwxXQogICAgICAgIHBvcDI8LWNvbWJbaSwyXQogICAgICAgIGRmPC1mc3QuY2hbZnN0LmNoJHBvcD09Y29tcGFyZVtpXSxdCiAgICAgICAgcGFpcmNoW3BvcDEscG9wMl08LW1lYW4oZGYkRnN0LCBuYS5ybT1UKQogICAgfQogICAgZGlhZyhwYWlyY2gpPC0wCiAgICBwYWlyY2gkcG9wPC1yb3duYW1lcyhwYWlyY2gpCiAgICBkZm08LW1lbHQocGFpcmNoLG5hLnJtPVQsIGlkLnZhcnM9J3BvcCcpCiAgICAKICAgICNOQSB0byBkaWFnb25hbAogICAgZGZtJHZhbHVlW2RmbSR2YWx1ZT09MF08LU5BCiAgICBkZm0kcG9wPC1mYWN0b3IoZGZtJHBvcCwgbGV2ZWxzPXBvcHMpCiAgICBkZm0kdmFsdWU8LXJvdW5kKGRmbSR2YWx1ZSwgNCkKICAgIGRmbSRjaHI8LWoKICAgIEZzdDwtcmJpbmQoRnN0LCBkZm0pCiAgICAKfQpGc3QkaWQ8LXBhc3RlMChGc3QkcG9wLCIgdnMuIixGc3QkdmFyaWFibGUpCkZzdDwtRnN0WyFpcy5uYShGc3QkdmFsdWUpLF0KZ2dwbG90KEZzdCwgYWVzKHg9Y2hyLCB5PXZhbHVlLGNvbG9yPWlkKSkrCiAgICBnZW9tX3BvaW50KCkrCiAgICBnZW9tX3BhdGgoc3RhdD0iaWRlbnRpdHkiKSsKICAgIHRoZW1lX21pbmltYWwoKSt5bGFiKCJGc3QiKSsKICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3M9MToyNiwgbGFiZWxzID0gMToyNikrCiAgICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSkKZ2dzYXZlKCIuLi9PdXRwdXQvU0ZTL1BXU19Gc3RfYnlDaHJvbW9zb21lX2RvdHBsb3QucG5nIiwgd2lkdGggPSA4LCBoZWlnaHQ9NC41LCBkcGk9MTUwKQpgYGAKIVtQV1MgYXZlcmFnZSBGc3QgcGVyIGNocm9tb3NvbWVdKC4uL091dHB1dC9TRlMvUFdTX0ZzdF9ieUNocm9tb3NvbWVfZG90cGxvdC5wbmcpe3dpZHRoPTgwJX0gIAoKPGJyPgoKIyMgVG9naWFrIEJheSAgCiMjIyBQYWlyd2lzZSBGc3QgYWxvbmcgdGhlIGdlbm9tZSAgCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpwb3BzPC1jKCJUQjkxIiwiVEI5NiIsIlRCMDYiLCJUQjE3IikKY29tYjwtdChjb21ibihwb3BzLDIpKQoKZnN0PC1kYXRhLmZyYW1lKCkKZm9yIChpIGluIDE6IG5yb3coY29tYikpewogICAgcG9wMTwtY29tYltpLDFdCiAgICBwb3AyPC1jb21iW2ksMl0KICAgIGRmPC1yZWFkLmRlbGltKHBhc3RlMCgiLi4vRGF0YS9uZXdfdmNmL2FuZ3NkL2Zyb21WQ0YvMkQvZnN0XyIscG9wMSwiXyIscG9wMiwiXzUwa1dpbmRvd19tYWYwMCIpKQogICAgY29uYW1lczwtY29sbmFtZXMoZGYpWzI6NF0KICAgIGNvbG5hbWVzKGRmKVs0XTwtIkZzdCIKICAgIGNvbG5hbWVzKGRmKVsxOjNdPC1jb25hbWVzCiAgICBkZiRwb3A8LXBhc3RlMChwb3AxLCIudnMuIixwb3AyKQogICAgZGYkY2g9YXMuaW50ZWdlcihnc3ViKCJjaHIiLCIiLCBkZiRjaHIpKQogICAgZGY8LWRmW29yZGVyKGRmJGNoKSxdCiAgICBkZiRsb2M8LTE6bnJvdyhkZikKICAgIGZzdDwtcmJpbmQoZnN0LCBkZikKfQpldmVuczwtcGFzdGUwKCJjaHIiLHNlcSgyLDI2LCBieT0yKSkKI1Bsb3QgRnN0IHZhbHVlcyBhY3Jvc3MgR2Vub21lCmZzdCRjb2xvcjwtImNvbDEiCmZzdCRjb2xvcltmc3QkY2hyICVpbiUgZXZlbnNdPC0iY29sMiIKZnN0JHBvcDwtZmFjdG9yKGZzdCRwb3AsIGxldmVscz11bmlxdWUoZnN0JHBvcCkpCgojYWRkIGNocm9tb3NvbWUgbnVtYmVyCmRmPC1mc3RbZnN0JHBvcD09IlRCOTEudnMuVEI5NiIsXQpyb3dzPC1kYXRhLmZyYW1lKGNocj0xOjI2KQpmb3IgKGkgaW4gMToyNil7CiAgICBpZiAoaSA9PTEpewogICAgICAgIHJvd3MkbltpXTwtbnJvdyhkZltkZiRjaD09aSxdKQogICAgICAgIHJvd3MkbWlkZGxlW2ldPC0tbnJvdyhkZltkZiRjaD09aSxdKS8yCiAgICB9CiAgICBpZiAoaSA+MSl7CiAgICAgICAgcm93cyRuW2ldPC1ucm93KGRmW2RmJGNoPT1pLF0pCiAgICAgICAgcm93cyRtaWRkbGVbaV08LXN1bShyb3dzJG5bMTooaS0xKV0pK3Jvd3MkbltpXS8yCiAgICB9Cn0KIwpnZ3Bsb3QoZnN0LCBhZXMoeD1sb2MsIHk9RnN0LCBjb2xvcj1jb2xvcikpKwogICAgZmFjZXRfd3JhcCh+cG9wLCBuY29sID0gMSwgc3RyaXAucG9zaXRpb249InJpZ2h0IikrCiAgICBnZW9tX3BvaW50KHNpemU9MC4yKSsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiZ3JheTUwIiwic3RlZWxibHVlIikpKwogICAgdGhlbWVfYncoKSsKICAgIHlsYWIoIkZzdCIpK3hsYWIoJ0dlbm9tZSBwb3NpdGlvbicpKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCksIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSkrCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPXJvd3MkbWlkZGxlLCBsYWJlbHM9MToyNikKZ2dzYXZlKCIuLi9PdXRwdXQvU0ZTL1RCX0ZzdF9wYWlyd2lzZV9jb21wYXJpc29uLnBuZyIsIHdpZHRoID0xOCAsIGhlaWdodCA9IDksIGRwaT0xNTApCmBgYAohW10oLi4vT3V0cHV0L1NGUy9UQl9Gc3RfcGFpcndpc2VfY29tcGFyaXNvbi5wbmcpICAKCiMjIyBQYWlyd2lzZSBGc3QgYWxvbmcgZWFjaCBjaHJvbW9zb21lCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMjIFBsb3QgRnN0IHZhbHVlcyBhbG9uZyBlYWNoIGNocm9tb3NvbWUKZnN0JGNocjwtZmFjdG9yKGZzdCRjaHIsIGxldmVscz1wYXN0ZTAoImNociIsMToyNikpCmZzdHRiPC1mc3QKcGxvdHM8LWxpc3QoKQpjb21wYXJlPC1wYXN0ZTAodW5pcXVlKGZzdHRiJHBvcCkpCmZvciAoaSBpbiAxOjYpeyAKICAgIGZzPC1nc3ViKCJ2cy4iLCIiLGNvbXBhcmVbaV0pCiAgICBwb3BzIDwtIHVubGlzdChzdHJzcGxpdChmcywgIlxcLiIpKQogICAgbWF4eTwtbWF4KGZzdHRiJEZzdFtmc3R0YiRwb3A9PWNvbXBhcmVbaV1dKQogICAgIyBGc3Qgd2l0aCBhY3R1YWwgbGluZSB0byBoaWdobGlnaHQgdGhlIGRpZmZlcmVuY2VzCiAgICBwbG90c1tbaV1dIDwtIGdncGxvdChmc3R0Yltmc3R0YiRwb3A9PWNvbXBhcmVbaV0sXSwgYWVzKHggPW1pZFBvcywgeSA9RnN0ICkpICsgCiAgICAgICAgZ2VvbV9wb2ludChzaXplID0gMSwgY29sb3IgPSBncnksYWxwaGEgPSAwLjQsIHNoYXBlID0gMSkrCiAgICAgICAgdGhlbWVfbWluaW1hbCgpK3lsaW0oMCxtYXh5KzAuMDIpKwogICAgICAgIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSkrCiAgICAgICAgeWxhYigiRnN0XG4iKSsgeGxhYigiIikrIAogICAgICAgIGdndGl0bGUocGFzdGUwKHBvcHNbMV0sIiB2cy4iLCBwb3BzWzJdKSkrCiAgICAgICAgZ2VvbV9saW5lKGNvbG9yPWJsdSwgc2l6ZT0wLjIpKwogICAgICAgIGZhY2V0X3dyYXAofmNociwgbmNvbCA9IDkpCn0KYGBgCgpgYGB7YmFzaCBldmFsPUZBTFNFfQojVG8gc2F2ZSB0aGUgcGxvdHMsIHJ1biBpbiBSCnBuZyhwYXN0ZTAoIk91dHB1dC9TRlMvVEJfRnN0X21hZjAwX2Noci5wbmciKSwgaGVpZ2h0ID0gOCwgd2lkdGggPSAxOCwgcmVzPTE1MCwgdW5pdHMgPSAiaW4iKSAgCmdyaWQuYXJyYW5nZShwbG90c1tbM11dLCBwbG90c1tbMl1dLCBwbG90c1tbNF1dLCBwbG90c1tbMV1dLHBsb3RzW1s1XV0scGxvdHNbWzZdXSwgbmNvbD0zKSAgCmRldi5vZmYoKSAgCmBgYAoKIVtdKC4uL091dHB1dC9TRlMvVEJfRnN0X21hZjAwX2Noci5wbmcpICAKCgojIyMgUGFpcndpc2UgRnN0IG1hdHJpeCAgCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfSAgCiMjIENvbnRpbnVlZCBmcm9tIHRoZSBhYm92ZQpwb3BzPC1jKCJUQjkxIiwiVEI5NiIsIlRCMDYiLCJUQjE3IikKY29tYjwtdChjb21ibihwb3BzLDIpKQoKIyMgUGxvdCBhdmVyYWdlIGZzdCBpbiBhIGhlYXRtYXAKY29tcGFyZTwtdW5pcXVlKGZzdCRwb3ApCnBhaXJmc3Q8LWRhdGEuZnJhbWUobWF0cml4KG5jb2w9NCwgbnJvdz00KSwgcm93Lm5hbWVzPXBvcHMpCmNvbG5hbWVzKHBhaXJmc3QpPC1wb3BzCmZvciAoaSBpbiAxOjYpewogICAgcG9wMTwtY29tYltpLDFdCiAgICBwb3AyPC1jb21iW2ksMl0KICAgIGRmPC1mc3RbZnN0JHBvcD09Y29tcGFyZVtpXSxdCiAgICBwYWlyZnN0W3BvcDEscG9wMl08LW1lYW4oZGYkRnN0LCBuYS5ybT1UKQp9CndyaXRlLmNzdihwYWlyZnN0LCIuLi9PdXRwdXQvU0ZTL1RCX3BhaXJ3aXNlRnN0X21hdHJpeC5jc3YiKQoKcGFpcmZzdDwtcmVhZC5jc3YoIi4uL091dHB1dC9TRlMvVEJfcGFpcndpc2VGc3RfbWF0cml4LmNzdiIsIHJvdy5uYW1lcyA9IDEpCgpkZjwtcGFpcmZzdApkaWFnKGRmKTwtMApkZiRwb3A8LXJvd25hbWVzKGRmKQpkZm08LW1lbHQoZGYsbmEucm09VCwgaWQudmFycz0ncG9wJykKI05BIHRvIGRpYWdvbmFsCmRmbSR2YWx1ZVtkZm0kdmFsdWU9PTBdPC1OQQpkZm0kcG9wPC1mYWN0b3IoZGZtJHBvcCwgbGV2ZWxzPXBvcHMpCmRmbSR2YWx1ZTwtcm91bmQoZGZtJHZhbHVlLCA0KQpnZ3Bsb3QoZGF0YSA9IGRmbSwgYWVzKHBvcCwgdmFyaWFibGUsIGZpbGwgPSB2YWx1ZSkpKwogICAgZ2VvbV90aWxlKGNvbG9yID0gIndoaXRlIikrCiAgICBzY2FsZV9maWxsX2dyYWRpZW50bihjb2xvcnM9Yygid2hpdGUiLCAiIzBDNTRGRiIpLCBsaW1pdHM9YygwLCAobWF4KGRmbSR2YWx1ZSwgbmEucm09VCkrMC4wMDUpKSxuYS52YWx1ZT0iZ3JheTgwIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lPSJGc3QiKSsKICAgIHRoZW1lX21pbmltYWwoKSsgeGxhYigiIikreWxhYigiIikrCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIHZqdXN0ID0gMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMTIsIGhqdXN0ID0gMC41KSkrCiAgICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpKSsKICAgIGNvb3JkX2ZpeGVkKCkrCiAgICBnZW9tX3RleHQoYWVzKHBvcCwgdmFyaWFibGUsIGxhYmVsID0gdmFsdWUpLCBjb2xvciA9ICJibGFjayIsIHNpemUgPSA1KQpnZ3NhdmUocGFzdGUwKCIuLi9PdXRwdXQvU0ZTL3BhaXJ3aXNlRnN0X1RCLnBuZyIpLCB3aWR0aCA9IDUsIGhlaWdodCA9IDUsIGRwaT0xNTApCmBgYAohW10oLi4vT3V0cHV0L1NGUy9wYWlyd2lzZUZzdF9UQi5wbmcpe3dpZHRoPTUwJX0gIAoKIyMjIEZzdCBjaGFuZ2Ugb3ZlciB0aW1lICAKCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgUGxvdCBGc3QgaW4gYSBiYXIgcGxvdCBvcmRlcmVkIGFuZCBjb2xvcmVkIGluIHRoZSBzYW1lIHdheSBhcyBGc3QvUGkgc2h1ZmZsZSByZXN1bHRzIChTaHVmZmxpbmdfcGkuZnN0LnRlaGF0LlJtZCkKZnN0czwtZGZtWyFpcy5uYShkZm0kdmFsdWUpLF0KZnN0cyRjb21wPC1wYXN0ZTAoZnN0cyRwb3AsIl8iLGZzdHMkdmFyaWFibGUpCgojc2V0IHRoZSBjb2xvcnMKI2RpdjE8LWRpdmVyZ2luZ19oY2woNiwgcGFsZXR0ZT0iQmx1ZS1SZWQiKQojZGl2MjwtcmV2KGRpdjEpCiNuYW1lcyhkaXYyKTwtYygiUFdTOTZfUFdTMDciLCJQV1MwN19QV1MxNyIsIlBXUzkxX1BXUzk2IiwgIlBXUzkxX1BXUzA3IiwgIlBXUzkxX1BXUzE3IiwiUFdTOTZfUFdTMTciKQpmc3RzPC1mc3RzW29yZGVyKGZzdHMkdmFsdWUsIGRlY3JlYXNpbmcgPSBUKSxdCmZzdHMkY29tcDwtZmFjdG9yKGZzdHMkY29tcCwgbGV2ZWxzPXBhc3RlMCh1bmlxdWUoZnN0cyRjb21wKSkpCgpnZ3Bsb3QoZnN0cywgYWVzKHg9Y29tcCwgeT12YWx1ZSwgZmlsbD1jb21wKSkrCiAgICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIpKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzID0gZGl2MSkrCiAgICB4bGFiKCcnKSt5bGFiKCdGc3QnKSsKICAgIHRoZW1lX2NsYXNzaWMoKSsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlPTQ1LCBoanVzdD0xKSwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQpnZ3NhdmUoIi4uL091dHB1dC9Gc3QvVEJfUGFpcndpc2VGc3Rfb3JkZXJlZC5wbmciLCB3aWR0aCA9IDQsIGhlaWdodCA9IDIuOCwgZHBpPTMwMCApCgojRnN0IG92ZXIgdGltZQpmc3RzMjwtZnN0c1tmc3RzJGNvbXAgJWluJSBjKCJUQjkxX1RCOTYiLCJUQjk2X1RCMDYiLCJUQjA2X1RCMTciKSxdCmZzdHMyJHRpbWU8LTEKZnN0czIkdGltZVtmc3RzMiRjb21wPT0iVEI5Nl9UQjA2Il08LTIKZnN0czIkdGltZVtmc3RzMiRjb21wPT0iVEIwNl9UQjE3Il08LTMKZnN0czI8LWZzdHMyW29yZGVyKGZzdHMyJHRpbWUpLF0KZ2dwbG90KGZzdHMyLCBhZXMoeD10aW1lLCB5PXZhbHVlKSkrCiAgICBnZW9tX3BvaW50KHNpemU9MywgY29sb3I9InN0ZWVsYmx1ZSIpKwogICAgZ2VvbV9wYXRoKCBhZXMoeD10aW1lLCB5PXZhbHVlKSxjb2xvcj0ic3RlZWxibHVlIikrCiAgICB0aGVtZV9jbGFzc2ljKCkreWxhYigiRnN0IikreGxhYigiIikrCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoMSwyLDMpLCBsYWJlbHM9YygiMTk5MS0xOTk2IiwgIjE5OTYtMjAwNiIsIjIwMDYtMjAxNyIpKQpnZ3NhdmUoIi4uL091dHB1dC9Gc3QvRnN0X292ZXJUaW1lX1RCLnBuZyIsIHdpZHRoID0gNCwgaGVpZ2h0ID0gMi44LCBkcGk9MzAwICkKCmZzdHMkc2VyaWVzPC0iMTk5MS0yMDA3LCAxOTkxLTIwMTciCmZzdHMkc2VyaWVzW2ZzdHMkY29tcCAlaW4lIGMoIlRCOTFfVEI5NiIsIlRCOTZfVEIwNiIsIlRCMDZfVEIxNyIpXTwtIjE5OTEtMTk5NiwgMTk5Ni0yMDA3LCAyMDA3LTIwMTciCmZzdHMkc2VyaWVzW2ZzdHMkY29tcCA9PSJUQjk2X1RCMTciXTwtIjE5OTYtMjAxNyIKZnN0cyR0aW1lPC0xCmZzdHMkdGltZVtmc3RzJHZhcmlhYmxlPT0iVEIxNyJdPC0zCmZzdHMkdGltZVtmc3RzJHZhcmlhYmxlPT0iVEIwNiJdPC0yCiNzb3VyY2UoIi4uL1JzY3JpcHRzL0Jhc2VTY3JpcHRzLlIiKQpmc3RzPC1mc3RzW29yZGVyKGZzdHMkdGltZSksXQpnZ3Bsb3QoZnN0cywgYWVzKHg9dGltZSwgeT12YWx1ZSwgY29sb3I9c2VyaWVzKSkrCiAgICBnZW9tX3BvaW50KHNpemU9MykrCiAgICBnZW9tX3BhdGgoKSsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9Y29scykrCiAgICB0aGVtZV9jbGFzc2ljKCkreWxhYigiRnN0IikreGxhYigiIikrCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoMSwyLDMpLCBsYWJlbHM9YygiMTk5MS0xOTk2IiwgIn4yMDA3IiwifjIwMTciKSkrCiAgICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCmdnc2F2ZSgiLi4vT3V0cHV0L0ZzdC9Gc3Rfb3ZlclRpbWVfVEJfYWxsQ29tcGFyaXNvbi5wbmciLCB3aWR0aCA9IDYsIGhlaWdodCA9IDIuOCwgZHBpPTMwMCApCgojIHBsb3QgYm90aCBQV1MgYW5kIFRCIHRvZ2V0aGVyCgpmc3RQMiRwb3A8LSJQV1MiCmZzdHMyJHBvcDwtIlRCIgpmc3RQVDwtcmJpbmQoZnN0UDIsIGZzdHMyKQoKZ2dwbG90KGZzdFBULCBhZXMoeD10aW1lLCB5PXZhbHVlLCBjb2xvcj1wb3ApKSsKICAgIGdlb21fcG9pbnQoc2l6ZT0zKSsKICAgIGdlb21fcGF0aCggYWVzKHg9dGltZSwgeT12YWx1ZSkpKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jb2xzW2MoMiwxKV0pKwogICAgdGhlbWVfY2xhc3NpYygpK3lsYWIoIkZzdCIpK3hsYWIoIiIpKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDEsMiwzKSwgbGFiZWxzPWMoIjE5OTEtMTk5NiIsICIxOTk2LTIwMDYiLCIyMDA2LTIwMTciKSkrCiAgICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCmdnc2F2ZSgiLi4vT3V0cHV0L0ZzdC9Gc3Rfb3ZlclRpbWVfUFdTX1RCLnBuZyIsIHdpZHRoID0gNCwgaGVpZ2h0ID0gMi44LCBkcGk9MzAwICkKCmZzdFQxPC1mc3RzCmZzdFQyPC1mc3RzMgpgYGAKCiFbXSguLi9PdXRwdXQvRnN0L0ZzdF9vdmVyVGltZV9UQi5wbmcpe3dpZHRoPTYwJX0KCgohW10oLi4vT3V0cHV0L0ZzdC9Gc3Rfb3ZlclRpbWVfVEJfYWxsQ29tcGFyaXNvbi5wbmcpe3dpZHRoPTc1JX0KCgohW10oLi4vT3V0cHV0L0ZzdC9Gc3Rfb3ZlclRpbWVfUFdTX1RCLnBuZyl7d2lkdGg9NjAlfQoKCiMjIyBNZWFuIHBhaXJzaWUgRnN0IHBlciBjaHJvbW9zb21lIApgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfSAgCiMgUGxvdCBtZWFuIEZzdCBvZiBlYWNoIGNocm9tb3NtZQpGc3Q8LWRhdGEuZnJhbWUoKQpmb3IgKGogaW4gMToyNil7CiAgICBmc3QuY2g8LWZzdFtmc3QkY2g9PWosXQogICAgcGFpcmNoPC1kYXRhLmZyYW1lKG1hdHJpeChuY29sPTQsIG5yb3c9NCksIHJvdy5uYW1lcz1wb3BzKQogICAgY29sbmFtZXMocGFpcmNoKTwtcG9wcwogICAgZm9yIChpIGluIDE6Nil7CiAgICAgICAgcG9wMTwtY29tYltpLDFdCiAgICAgICAgcG9wMjwtY29tYltpLDJdCiAgICAgICAgZGY8LWZzdC5jaFtmc3QuY2gkcG9wPT1jb21wYXJlW2ldLF0KICAgICAgICBwYWlyY2hbcG9wMSxwb3AyXTwtbWVhbihkZiRGc3QsIG5hLnJtPVQpCiAgICB9CiAgICBkaWFnKHBhaXJjaCk8LTAKICAgIHBhaXJjaCRwb3A8LXJvd25hbWVzKHBhaXJjaCkKICAgIGRmbTwtbWVsdChwYWlyY2gsbmEucm09VCwgaWQudmFycz0ncG9wJykKICAgIAogICAgI05BIHRvIGRpYWdvbmFsCiAgICBkZm0kdmFsdWVbZGZtJHZhbHVlPT0wXTwtTkEKICAgIGRmbSRwb3A8LWZhY3RvcihkZm0kcG9wLCBsZXZlbHM9cG9wcykKICAgIGRmbSR2YWx1ZTwtcm91bmQoZGZtJHZhbHVlLCA0KQogICAgZGZtJGNocjwtagogICAgRnN0PC1yYmluZChGc3QsIGRmbSkKICAgIAp9CkZzdCRpZDwtcGFzdGUwKEZzdCRwb3AsIiB2cy4iLEZzdCR2YXJpYWJsZSkKRnN0PC1Gc3RbIWlzLm5hKEZzdCR2YWx1ZSksXQpnZ3Bsb3QoRnN0LCBhZXMoeD1jaHIsIHk9dmFsdWUsY29sb3I9aWQpKSsKICAgIGdlb21fcG9pbnQoKSsKICAgIGdlb21fcGF0aChzdGF0PSJpZGVudGl0eSIpKwogICAgdGhlbWVfbWluaW1hbCgpK3lsYWIoIkZzdCIpKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz0xOjI2LCBsYWJlbHMgPSAxOjI2KSsKICAgIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpKQpnZ3NhdmUoIi4uL091dHB1dC9TRlMvVEJfRnN0X2J5Q2hyb21vc29tZV9kb3RwbG90LnBuZyIsIHdpZHRoID0gMTMsIGhlaWdodD02LjUsIGRwaT0xNTApCmBgYAoKIVtUQiBtZWFuIEZzdCBwZXIgY2hyb21vc29tZV0oLi4vT3V0cHV0L1NGUy9UQl9Gc3RfYnlDaHJvbW9zb21lX2RvdHBsb3QucG5nKQoKPGJyPgoKIyMgU2l0a2EgU291bmQgIAojIyMgUGFpcndpc2UgRnN0IGFsb25nIHRoZSBnZW5vbWUgIAoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCnBvcHM8LWMoIlNTOTYiLCJTUzA2IiwiU1MxNyIpCmNvbWI8LXQoY29tYm4ocG9wcywyKSkKCmZzdDwtZGF0YS5mcmFtZSgpCmZvciAoaSBpbiAxOiBucm93KGNvbWIpKXsKICAgIHBvcDE8LWNvbWJbaSwxXQogICAgcG9wMjwtY29tYltpLDJdCiAgICBkZjwtcmVhZC5kZWxpbShwYXN0ZTAoIi4uL0RhdGEvbmV3X3ZjZi9hbmdzZC9mcm9tVkNGLzJEL2ZzdF8iLHBvcDEsIl8iLHBvcDIsIl81MGtXaW5kb3dfbWFmMDAiKSkKICAgIGNvbmFtZXM8LWNvbG5hbWVzKGRmKVsyOjRdCiAgICBjb2xuYW1lcyhkZilbNF08LSJGc3QiCiAgICBjb2xuYW1lcyhkZilbMTozXTwtY29uYW1lcwogICAgZGYkcG9wPC1wYXN0ZTAocG9wMSwiLnZzLiIscG9wMikKICAgIGRmJGNoPWFzLmludGVnZXIoZ3N1YigiY2hyIiwiIiwgZGYkY2hyKSkKICAgIGRmPC1kZltvcmRlcihkZiRjaCksXQogICAgZGYkbG9jPC0xOm5yb3coZGYpCiAgICBmc3Q8LXJiaW5kKGZzdCwgZGYpCn0KCmV2ZW5zPC1wYXN0ZTAoImNociIsc2VxKDIsMjYsIGJ5PTIpKQojUGxvdCBGc3QgdmFsdWVzIGFjcm9zcyBHZW5vbWUKZnN0JGNvbG9yPC0iY29sMSIKZnN0JGNvbG9yW2ZzdCRjaHIgJWluJSBldmVuc108LSJjb2wyIgpmc3QkcG9wPC1mYWN0b3IoZnN0JHBvcCwgbGV2ZWxzPXVuaXF1ZShmc3QkcG9wKSkKCiNhZGQgY2hyb21vc29tZSBudW1iZXIKZGY8LWZzdFtmc3QkcG9wPT0iU1M5Ni52cy5TUzA2IixdCnJvd3M8LWRhdGEuZnJhbWUoY2hyPTE6MjYpCmZvciAoaSBpbiAxOjI2KXsKICAgIGlmIChpID09MSl7CiAgICAgICAgcm93cyRuW2ldPC1ucm93KGRmW2RmJGNoPT1pLF0pCiAgICAgICAgcm93cyRtaWRkbGVbaV08LS1ucm93KGRmW2RmJGNoPT1pLF0pLzIKICAgIH0KICAgIGlmIChpID4xKXsKICAgICAgICByb3dzJG5baV08LW5yb3coZGZbZGYkY2g9PWksXSkKICAgICAgICByb3dzJG1pZGRsZVtpXTwtc3VtKHJvd3MkblsxOihpLTEpXSkrcm93cyRuW2ldLzIKICAgIH0KfQojCmdncGxvdChmc3QsIGFlcyh4PWxvYywgeT1Gc3QsIGNvbG9yPWNvbG9yKSkrCiAgICBmYWNldF93cmFwKH5wb3AsIG5jb2wgPSAxLCBzdHJpcC5wb3NpdGlvbj0icmlnaHQiKSsKICAgIGdlb21fcG9pbnQoc2l6ZT0wLjIpKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJncmF5NTAiLCJzdGVlbGJsdWUiKSkrCiAgICB0aGVtZV9idygpKwogICAgeWxhYigiRnN0IikreGxhYignR2Vub21lIHBvc2l0aW9uJykrCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSwgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpKSsKICAgIHNjYWxlX3hfY29udGludW91cyhicmVha3M9cm93cyRtaWRkbGUsIGxhYmVscz0xOjI2KQpnZ3NhdmUoIi4uL091dHB1dC9TRlMvU1NfRnN0X3BhaXJ3aXNlX2NvbXBhcmlzb24ucG5nIiwgd2lkdGggPSAxNiwgaGVpZ2h0ID0gNywgZHBpPTE1MCkKYGBgCiFbXSguLi9PdXRwdXQvU0ZTL1NTX0ZzdF9wYWlyd2lzZV9jb21wYXJpc29uLnBuZykgIAogIAogICAKIyMjIFBhaXJ3aXNlIEZzdCBhbG9uZyBlYWNoIGNocm9tb3NvbWUKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZXZhbD1GQUxTRX0KIyMgUGxvdCBGc3QgdmFsdWVzIGFsb25nIGVhY2ggY2hyb21vc29tZQpmc3QkY2hyPC1mYWN0b3IoZnN0JGNociwgbGV2ZWxzPXBhc3RlMCgiY2hyIiwxOjI2KSkKZnN0c3M8LWZzdApwbG90czwtbGlzdCgpCmNvbXBhcmU8LXBhc3RlMCh1bmlxdWUoZnN0c3MkcG9wKSkKZm9yIChpIGluIDE6Myl7IAogICAgZnM8LWdzdWIoInZzLiIsIiIsY29tcGFyZVtpXSkKICAgIHBvcHMgPC0gdW5saXN0KHN0cnNwbGl0KGZzLCAiXFwuIikpCiAgICBtYXh5PC1tYXgoZnN0c3MkRnN0W2ZzdHNzJHBvcD09Y29tcGFyZVtpXV0pCiAgICAjIEZzdCB3aXRoIGFjdHVhbCBsaW5lIHRvIGhpZ2hsaWdodCB0aGUgZGlmZmVyZW5jZXMKICAgIHBsb3RzW1tpXV0gPC0gZ2dwbG90KGZzdHNzW2ZzdHNzJHBvcD09Y29tcGFyZVtpXSxdLCBhZXMoeCA9bWlkUG9zLCB5ID1Gc3QgKSkgKyAKICAgICAgICBnZW9tX3BvaW50KHNpemUgPSAxLCBjb2xvciA9IGdyeSxhbHBoYSA9IDAuNCwgc2hhcGUgPSAxKSsKICAgICAgICB0aGVtZV9taW5pbWFsKCkreWxpbSgwLG1heHkrMC4wMikrCiAgICAgICAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpKSsKICAgICAgICB5bGFiKCJGc3RcbiIpKyB4bGFiKCIiKSsgCiAgICAgICAgZ2d0aXRsZShwYXN0ZTAocG9wc1sxXSwiIHZzLiIsIHBvcHNbMl0pKSsKICAgICAgICBnZW9tX2xpbmUoY29sb3I9Ymx1LCBzaXplPTAuMikrCiAgICAgICAgZmFjZXRfd3JhcCh+Y2hyLCBuY29sID0gOSkKfQoKe3BuZyhwYXN0ZTAoIk91dHB1dC9TRlMvU1NfRnN0X21hZjAwX2Noci5wbmciKSwgaGVpZ2h0ID0gNCwgd2lkdGggPSAxOCwgcmVzPTE1MCwgdW5pdHMgPSAiaW4iKSAgCmdyaWQuYXJyYW5nZShwbG90c1tbMV1dLCBwbG90c1tbMl1dLCBwbG90c1tbM11dLCBuY29sPTMpICAKZGV2Lm9mZigpICB9CmBgYAoKIVtdKC4uL091dHB1dC9TRlMvU1NfRnN0X21hZjAwX2Noci5wbmcpICAKICAKIyMjIFBhaXJ3aXNlIEZzdCBtYXRyaXggIAoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyMgQ29udGludWVkIGZyb20gdGhlIGFib3ZlCnBvcHM8LWMoIlNTOTYiLCJTUzA2IiwiU1MxNyIpCmNvbWI8LXQoY29tYm4ocG9wcywyKSkKCiMjIFBsb3QgYXZlcmFnZSBmc3QgaW4gYSBoZWF0bWFwCmNvbXBhcmU8LXVuaXF1ZShmc3QkcG9wKQpwYWlyZnN0PC1kYXRhLmZyYW1lKG1hdHJpeChuY29sPTMsIG5yb3c9MyksIHJvdy5uYW1lcz1wb3BzKQpjb2xuYW1lcyhwYWlyZnN0KTwtcG9wcwpmb3IgKGkgaW4gMTozKXsKICAgIHBvcDE8LWNvbWJbaSwxXQogICAgcG9wMjwtY29tYltpLDJdCiAgICBkZjwtZnN0W2ZzdCRwb3A9PWNvbXBhcmVbaV0sXQogICAgcGFpcmZzdFtwb3AxLHBvcDJdPC1tZWFuKGRmJEZzdCwgbmEucm09VCkKfQp3cml0ZS5jc3YocGFpcmZzdCwiLi4vT3V0cHV0L1NGUy9TU19wYWlyd2lzZUZzdF9tYXRyaXguY3N2IikKCnBhaXJmc3Q8LXJlYWQuY3N2KCIuLi9PdXRwdXQvU0ZTL1NTX3BhaXJ3aXNlRnN0X21hdHJpeC5jc3YiLCByb3cubmFtZXMgPSAxKQpkZjwtcGFpcmZzdApkaWFnKGRmKTwtMApkZiRwb3A8LXJvd25hbWVzKGRmKQpkZm08LW1lbHQoZGYsbmEucm09VCwgaWQudmFycz0ncG9wJykKI05BIHRvIGRpYWdvbmFsCmRmbSR2YWx1ZVtkZm0kdmFsdWU9PTBdPC1OQQpkZm0kcG9wPC1mYWN0b3IoZGZtJHBvcCwgbGV2ZWxzPXBvcHMpCmRmbSR2YWx1ZTwtcm91bmQoZGZtJHZhbHVlLCA0KQpnZ3Bsb3QoZGF0YSA9IGRmbSwgYWVzKHBvcCwgdmFyaWFibGUsIGZpbGwgPSB2YWx1ZSkpKwogICAgZ2VvbV90aWxlKGNvbG9yID0gIndoaXRlIikrCiAgICBzY2FsZV9maWxsX2dyYWRpZW50bihjb2xvcnM9Yygid2hpdGUiLCAiIzBDNTRGRiIpLCBsaW1pdHM9YygwLCAobWF4KGRmbSR2YWx1ZSwgbmEucm09VCkrMC4wMDUpKSxuYS52YWx1ZT0iZ3JheTgwIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lPSJGc3QiKSsKICAgIHRoZW1lX21pbmltYWwoKSsgeGxhYigiIikreWxhYigiIikrCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIHZqdXN0ID0gMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMTIsIGhqdXN0ID0gMC41KSkrCiAgICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpKSsKICAgIGNvb3JkX2ZpeGVkKCkrCiAgICBnZW9tX3RleHQoYWVzKHBvcCwgdmFyaWFibGUsIGxhYmVsID0gdmFsdWUpLCBjb2xvciA9ICJibGFjayIsIHNpemUgPSA1KQpnZ3NhdmUocGFzdGUwKCIuLi9PdXRwdXQvU0ZTL3BhaXJ3aXNlRnN0X1NTLnBuZyIpLCB3aWR0aCA9IDUsIGhlaWdodCA9IDUsIGRwaT0xNTApCmBgYAohW10oLi4vT3V0cHV0L1NGUy9wYWlyd2lzZUZzdF9TUy5wbmcpe3dpZHRoPTYwJX0gIAoKCiMjIyBGc3QgY2hhbmdlIG92ZXIgdGltZQoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBQbG90IEZzdCBpbiBhIGJhciBwbG90IG9yZGVyZWQgYW5kIGNvbG9yZWQgaW4gdGhlIHNhbWUgd2F5IGFzIEZzdC9QaSBzaHVmZmxlIHJlc3VsdHMgKFNodWZmbGluZ19waS5mc3QudGVoYXQuUm1kKQpmc3RzPC1kZm1bIWlzLm5hKGRmbSR2YWx1ZSksXQpmc3RzJGNvbXA8LXBhc3RlMChmc3RzJHBvcCwiXyIsZnN0cyR2YXJpYWJsZSkKCiNzZXQgdGhlIGNvbG9ycwojZGl2MTwtZGl2ZXJnaW5nX2hjbCg2LCBwYWxldHRlPSJCbHVlLVJlZCIpCiNkaXYyPC1yZXYoZGl2MSkKI25hbWVzKGRpdjIpPC1jKCJQV1M5Nl9QV1MwNyIsIlBXUzA3X1BXUzE3IiwiUFdTOTFfUFdTOTYiLCAiUFdTOTFfUFdTMDciLCAiUFdTOTFfUFdTMTciLCJQV1M5Nl9QV1MxNyIpCmZzdHM8LWZzdHNbb3JkZXIoZnN0cyR2YWx1ZSwgZGVjcmVhc2luZyA9IFQpLF0KZnN0cyRjb21wPC1mYWN0b3IoZnN0cyRjb21wLCBsZXZlbHM9cGFzdGUwKHVuaXF1ZShmc3RzJGNvbXApKSkKCmdncGxvdChmc3RzLCBhZXMoeD1jb21wLCB5PXZhbHVlLCBmaWxsPWNvbXApKSsKICAgIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5IikrCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBkaXYxKSsKICAgIHhsYWIoJycpK3lsYWIoJ0ZzdCcpKwogICAgdGhlbWVfY2xhc3NpYygpKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0PTEpLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCmdnc2F2ZSgiLi4vT3V0cHV0L0ZzdC9UQl9QYWlyd2lzZUZzdF9vcmRlcmVkLnBuZyIsIHdpZHRoID0gMy40LCBoZWlnaHQgPSAyLjgsIGRwaT0zMDAgKQoKI0ZzdCBvdmVyIHRpbWUKZnN0czI8LWZzdHNbZnN0cyRjb21wICVpbiUgYygiU1M5Nl9TUzA2IiwiU1MwNl9TUzE3IiksXQpmc3RzMiR0aW1lPC0xCmZzdHMyJHRpbWVbZnN0czIkY29tcD09IlNTOTZfU1MwNiJdPC0yCmZzdHMyJHRpbWVbZnN0czIkY29tcD09IlNTMDZfU1MxNyJdPC0zCmZzdHMyPC1mc3RzMltvcmRlcihmc3RzMiR0aW1lKSxdCmdncGxvdChmc3RzMiwgYWVzKHg9dGltZSwgeT12YWx1ZSkpKwogICAgZ2VvbV9wb2ludChzaXplPTMsIGNvbG9yPSJzdGVlbGJsdWUiKSsKICAgIGdlb21fcGF0aCggYWVzKHg9dGltZSwgeT12YWx1ZSksY29sb3I9InN0ZWVsYmx1ZSIpKwogICAgdGhlbWVfY2xhc3NpYygpK3lsYWIoIkZzdCIpK3hsYWIoIiIpKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDEsMiwzKSwgbGFiZWxzPWMoIjE5OTEtMTk5NiIsICIxOTk2LTIwMDYiLCIyMDA2LTIwMTciKSkKZ2dzYXZlKCIuLi9PdXRwdXQvRnN0L0ZzdF9vdmVyVGltZV9TUy5wbmciLCB3aWR0aCA9IDMuNSwgaGVpZ2h0ID0gMi44LCBkcGk9MzAwICkKCmZzdHMkc2VyaWVzPC0iMTk5MS0yMDA3LCAxOTkxLTIwMTciCmZzdHMkc2VyaWVzW2ZzdHMkY29tcCA9PSJTUzk2X1NTMTciXTwtIjE5OTYtMjAxNyIKZnN0cyR0aW1lPC0xCmZzdHMkdGltZVtmc3RzJHZhcmlhYmxlPT0iU1MxNyJdPC0zCmZzdHMkdGltZVtmc3RzJHZhcmlhYmxlPT0iU1MwNiJdPC0yCiNzb3VyY2UoIi4uL1JzY3JpcHRzL0Jhc2VTY3JpcHRzLlIiKQpmc3RzPC1mc3RzW29yZGVyKGZzdHMkdGltZSksXQpnZ3Bsb3QoZnN0cywgYWVzKHg9dGltZSwgeT12YWx1ZSwgY29sb3I9c2VyaWVzKSkrCiAgICBnZW9tX3BvaW50KHNpemU9MykrCiAgICBnZW9tX3BhdGgoKSsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9Y29scykrCiAgICB0aGVtZV9jbGFzc2ljKCkreWxhYigiRnN0IikreGxhYigiIikrCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoMSwyLDMpLCBsYWJlbHM9YygiMTk5MS0xOTk2IiwgIn4yMDA3IiwifjIwMTciKSkrCiAgICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCmdnc2F2ZSgiLi4vT3V0cHV0L0ZzdC9Gc3Rfb3ZlclRpbWVfU1NfYWxsQ29tcGFyaXNvbi5wbmciLCB3aWR0aCA9IDYsIGhlaWdodCA9IDIuOCwgZHBpPTMwMCApCgoKIyBwbG90IGFsbCAzIHBvcHMgdG9nZXRoZXIKCmZzdFBUUzwtcmJpbmQoZnN0UFQsZnN0czIpCndyaXRlLmNzdihmc3RQVFMsICIuLi9PdXRwdXQvRnN0L01lYW5fRnN0X292ZXJUaW1lXzNwb3BzLmNzdiIsIHJvdy5uYW1lcyA9IEYpCgoKZnN0UFNUPC1yZWFkLmNzdigiLi4vT3V0cHV0L0ZzdC9NZWFuX0ZzdF9vdmVyVGltZV8zcG9wcy5jc3YiKQoKZ2dwbG90KGZzdFBTVCwgYWVzKHg9dGltZSwgeT12YWx1ZSwgY29sb3I9cG9wKSkrCiAgICBnZW9tX3BvaW50KHNpemU9MykrCiAgICBnZW9tX3BhdGgoIGFlcyh4PXRpbWUsIHk9dmFsdWUpKSsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9Y29sc1tjKDIsMSwzKV0pKwogICAgdGhlbWVfY2xhc3NpYygpK3lsYWIoIkZzdCIpK3hsYWIoIiIpKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDEsMiwzKSwgbGFiZWxzPWMoIjE5OTEtMTk5NiIsICIxOTk2LTIwMDYiLCIyMDA2LTIwMTciKSkrCiAgICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCmdnc2F2ZSgiLi4vT3V0cHV0L0ZzdC9Gc3Rfb3ZlclRpbWVfM1BvcHMucG5nIiwgd2lkdGggPSA1LCBoZWlnaHQgPSAyLjgsIGRwaT0zMDAgKQoKZnN0UDEkcG9wPC0iUFdTIgpmc3RUMSRwb3A8LSJUQiIKZnN0cyRwb3A8LSJTUyIKZnN0czM8LXJiaW5kKGZzdFAxLCBmc3RUMSwgZnN0cykKd3JpdGUuY3N2KGZzdHMzLCAiLi4vT3V0cHV0L0ZzdC9NZWFuX0ZzdF9vdmVyVGltZV8zcG9wc19hbGxjb21wLmNzdiIpCmBgYAohW10oLi4vT3V0cHV0L0ZzdC9Gc3Rfb3ZlclRpbWVfM1BvcHMucG5nKXt3aWR0aD02MCV9CgoKIyMjIE1lYW4gcGFpcnNpZSBGc3QgcGVyIGNocm9tb3NvbWUgIAoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZXZhbD1GQUxTRX0gIAojIFBsb3QgbWVhbiBGc3Qgb2YgZWFjaCBjaHJvbW9zb21lcwpGc3Q8LWRhdGEuZnJhbWUoKQpmb3IgKGogaW4gMToyNil7CiAgICBmc3QuY2g8LWZzdFtmc3QkY2g9PWosXQogICAgcGFpcmNoPC1kYXRhLmZyYW1lKG1hdHJpeChuY29sPTMsIG5yb3c9MyksIHJvdy5uYW1lcz1wb3BzKQogICAgY29sbmFtZXMocGFpcmNoKTwtcG9wcwogICAgZm9yIChpIGluIDE6Myl7CiAgICAgICAgcG9wMTwtY29tYltpLDFdCiAgICAgICAgcG9wMjwtY29tYltpLDJdCiAgICAgICAgZGY8LWZzdC5jaFtmc3QuY2gkcG9wPT1jb21wYXJlW2ldLF0KICAgICAgICBwYWlyY2hbcG9wMSxwb3AyXTwtbWVhbihkZiRGc3QsIG5hLnJtPVQpCiAgICB9CiAgICBkaWFnKHBhaXJjaCk8LTAKICAgIHBhaXJjaCRwb3A8LXJvd25hbWVzKHBhaXJjaCkKICAgIGRmbTwtbWVsdChwYWlyY2gsbmEucm09VCwgaWQudmFycz0ncG9wJykKICAgIAogICAgI05BIHRvIGRpYWdvbmFsCiAgICBkZm0kdmFsdWVbZGZtJHZhbHVlPT0wXTwtTkEKICAgIGRmbSRwb3A8LWZhY3RvcihkZm0kcG9wLCBsZXZlbHM9cG9wcykKICAgIGRmbSR2YWx1ZTwtcm91bmQoZGZtJHZhbHVlLCA0KQogICAgZGZtJGNocjwtagogICAgRnN0PC1yYmluZChGc3QsIGRmbSkKICAgIAp9CkZzdCRpZDwtcGFzdGUwKEZzdCRwb3AsIiB2cy4iLEZzdCR2YXJpYWJsZSkKRnN0PC1Gc3RbIWlzLm5hKEZzdCR2YWx1ZSksXQpnZ3Bsb3QoRnN0LCBhZXMoeD1jaHIsIHk9dmFsdWUsY29sb3I9aWQpKSsKICAgIGdlb21fcG9pbnQoKSsKICAgIGdlb21fcGF0aChzdGF0PSJpZGVudGl0eSIpKwogICAgdGhlbWVfbWluaW1hbCgpK3lsYWIoIkZzdCIpKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz0xOjI2LCBsYWJlbHMgPSAxOjI2KSsKICAgIHRoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpKQpnZ3NhdmUoIi4uL091dHB1dC9TRlMvU1NfRnN0X2J5Q2hyb21vc29tZV9kb3RwbG90LnBuZyIsIHdpZHRoID0gOCwgaGVpZ2h0PTQuNSwgZHBpPTE1MCkKYGBgCiFbXSguLi9PdXRwdXQvU0ZTL1NTX0ZzdF9ieUNocm9tb3NvbWVfZG90cGxvdC5wbmcpCgoKCgojIEZzdCBiZXR3ZWVuIHBvcHVsYXRpb25zICgyMDE3KSAKCiMjIFBhaXJpd3NlIEZzdCBhbG9uZyB0aGUgZ2Vub21lICAKCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnBvcHNuPC1yZWFkLmNzdigiLi4vRGF0YS9TYW1wbGVfbWV0YWRhdGFfODkycG9wcy5jc3YiKQpwb3BzPC11bmlxdWUocG9wc24kUG9wdWxhdGlvbi5ZZWFyKQp5MTc8LXBvcHNbZ3JlcCgiMTciLHBvcHMpXQoKY29tYjwtY29tYm4oeTE3LCAyKQpjb21iPC10KGNvbWIpCgojWWVhcjIwMTcKZnN0MTc8LWRhdGEuZnJhbWUoKQpmb3IgKGkgaW4gMTogbnJvdyhjb21iKSl7CiAgICBwb3AxPC1jb21iW2ksMV0KICAgIHBvcDI8LWNvbWJbaSwyXQogICAgZGY8LXJlYWQuZGVsaW0ocGFzdGUwKCIuLi9EYXRhL25ld192Y2YvYW5nc2QvZnJvbVZDRi8yRC9mc3RfZm9sZGVkXyIscG9wMSwiXyIscG9wMiwiXzUwa1dpbmRvd19tYWYwMCIpKQogICAgY29uYW1lczwtY29sbmFtZXMoZGYpWzI6NF0KICAgIGNvbG5hbWVzKGRmKVs0XTwtIkZzdCIKICAgIGNvbG5hbWVzKGRmKVsxOjNdPC1jb25hbWVzCiAgICBkZiRwb3A8LXBhc3RlMChwb3AxLCIudnMuIixwb3AyKQogICAgZGYkY2g9YXMuaW50ZWdlcihnc3ViKCJjaHIiLCIiLCBkZiRjaHIpKQogICAgZGY8LWRmW29yZGVyKGRmJGNoKSxdCiAgICBkZiRsb2M8LTE6bnJvdyhkZikKICAgIGZzdDE3PC1yYmluZChmc3QxNywgZGYpCn0KCndyaXRlLmNzdihmc3QxNywiLi4vT3V0cHV0L1NGUy9Gc3Rfd2luZG93X3llYXIyMDE3X2FsbHBvcHMuY3N2IikKCmZzdDE3JGNoPC1hcy5pbnRlZ2VyKGdzdWIoImNociIsIiIsZnN0MTckY2hyKSkKZnN0MTc8LWZzdDE3W29yZGVyKGZzdDE3JGNoLCBmc3QxNyRtaWRQb3MpLF0KZnN0MTckY2hyPC1mYWN0b3IoZnN0MTckY2hyLCBsZXZlbHM9cGFzdGUwKCJjaHIiLDE6MjYpKQoKcGFpcnM8LXVuaXF1ZShmc3QxNyRwb3ApCnBsb3RzPC1saXN0KCkKZm9yIChpIGluIDE6bGVuZ3RoKHBhaXJzKSl7IAogICAgZnM8LWdzdWIoIi52cyIsIiIscGFpcnNbaV0pCiAgICBwb3BzIDwtIHVubGlzdChzdHJzcGxpdChmcywgIlxcLiIpKQogICAgIyBGc3Qgd2l0aCBhY3R1YWwgbGluZSB0byBoaWdobGlnaHQgdGhlIGRpZmZlcmVuY2VzCiAgICBkZjwtZnN0MTdbZnN0MTckcG9wPT1wYWlyc1tpXSxdCiAgICBwbG90c1tbaV1dIDwtIGdncGxvdChkZiwgYWVzKHggPW1pZFBvcywgeSA9IEZzdCkpICsgCiAgICAgICAgZ2VvbV9wb2ludChzaXplID0gMSwgY29sb3IgPSAiZ3JheSIsYWxwaGEgPSAwLjQsIHNoYXBlID0gMSkrCiAgICAgICAgdGhlbWVfbWluaW1hbCgpKwogICAgICAgIHRoZW1lKGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSkrCiAgICAgICAgeWxhYigiRnN0XG4iKSsgeGxhYigiIikrIAogICAgICAgIGdndGl0bGUocGFzdGUwKHBvcHNbMV0sIiB2cy4iLCBwb3BzWzJdKSkrCiAgICAgICAgZ2VvbV9saW5lKGNvbG9yPSJzdGVlbGJsdWUiLCBzaXplPTAuMikrCiAgICAgICAgZmFjZXRfd3JhcCh+Y2hyLCBuY29sID0gOSkKfQoKI1NhbWUgeS1heGlzCnBsb3RzMjwtbGlzdCgpCiNUQiB5bGltPTAuOAojbm9uVEIgMC42CmZvciAoaSBpbiAxOmxlbmd0aChwYWlycykpeyAKICAgIGZzPC1nc3ViKCIudnMiLCIiLHBhaXJzW2ldKQogICAgcG9wcyA8LSB1bmxpc3Qoc3Ryc3BsaXQoZnMsICJcXC4iKSkKICAgICMgRnN0IHdpdGggYWN0dWFsIGxpbmUgdG8gaGlnaGxpZ2h0IHRoZSBkaWZmZXJlbmNlcwogICAgZGY8LWZzdDE3W2ZzdDE3JHBvcD09cGFpcnNbaV0sXQogICAgaWYgKGkgJWluJSBjKDQsOCwxMSwxMywxNSkpIHltYXg9MC44CiAgICBlbHNlIHltYXg9MC42CiAgICBwbG90czJbW2ldXSA8LSBnZ3Bsb3QoZGYsIGFlcyh4ID1taWRQb3MsIHkgPSBGc3QpKSArIAogICAgICAgIGdlb21fcG9pbnQoc2l6ZSA9IDEsIGNvbG9yID0gImdyYXkiLGFscGhhID0gMC40LCBzaGFwZSA9IDEpKwogICAgICAgIHRoZW1lX21pbmltYWwoKSt5bGltKDAseW1heCkrCiAgICAgICAgdGhlbWUoYXhpcy50ZXh0Lng9ZWxlbWVudF9ibGFuaygpKSsKICAgICAgICB5bGFiKCJGc3RcbiIpKyB4bGFiKCIiKSsgCiAgICAgICAgZ2d0aXRsZShwYXN0ZTAocG9wc1sxXSwiIHZzLiIsIHBvcHNbMl0pKSsKICAgICAgICBnZW9tX2xpbmUoY29sb3I9InN0ZWVsYmx1ZSIsIHNpemU9MC4yKSsKICAgICAgICBmYWNldF93cmFwKH5jaHIsIG5jb2wgPSA5KQp9CgpgYGAKCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQp7cG5nKHBhc3RlMCgiLi4vT3V0cHV0L1NGUy9ZZWFyMjAxN19Gc3QxLnBuZyIpLCBoZWlnaHQgPSA4LCB3aWR0aCA9IDIwLCByZXM9MTUwLCB1bml0cyA9ICJpbiIpCmRvLmNhbGwoZ3JpZC5hcnJhbmdlLCBjKHBsb3RzWzE6Nl0sIG5jb2w9MykpCmRldi5vZmYoKX0KCntwbmcocGFzdGUwKCIuLi9PdXRwdXQvU0ZTL1llYXIyMDE3X0ZzdDIucG5nIiksIGhlaWdodCA9IDEyLCB3aWR0aCA9IDIwLCByZXM9MTUwLCB1bml0cyA9ICJpbiIpCmRvLmNhbGwoZ3JpZC5hcnJhbmdlLCBjKHBsb3RzWzc6MTVdLCBuY29sPTMpKQpkZXYub2ZmKCl9CgojcGxvdCBub24tVEIKe3BuZyhwYXN0ZTAoIi4uL091dHB1dC9TRlMvWWVhcjIwMTdfRnN0X3NhbWVZYXhpcy5wbmciKSwgaGVpZ2h0ID0gMTYsIHdpZHRoID0gMjAsIHJlcz0xNTAsIHVuaXRzID0gImluIikKZG8uY2FsbChncmlkLmFycmFuZ2UsIGMocGxvdHMyW2MoMSwyLDMsNSw2LDcsOSwxMCwxMiwxNCldLCBuY29sPTMpKQpkZXYub2ZmKCl9Cgp7cG5nKHBhc3RlMCgiLi4vT3V0cHV0L1NGUy9ZZWFyMjAxN19Gc3Rfc2FtZVlheGlzMl9UQi5wbmciKSwgaGVpZ2h0ID0gMTIsIHdpZHRoID0gMjAsIHJlcz0xNTAsIHVuaXRzID0gImluIikKZG8uY2FsbChncmlkLmFycmFuZ2UsIGMocGxvdHMyW2MoNCw4LDExLDEzLDE1KV0sIG5jb2w9MykpCmRldi5vZmYoKX0KYGBgCgohW2NvbnRyYXN0IHdpdGhvdXQgVEJdKC4uL091dHB1dC9TRlMvWWVhcjIwMTdfRnN0X3NhbWVZYXhpcy5wbmcpCgohW0NvbnRyYXN0IGFnYWluc3QgVEIgcG9wXSguLi9PdXRwdXQvU0ZTL1llYXIyMDE3X0ZzdF9zYW1lWWF4aXMyX1RCLnBuZykKCgojIyBQYWl3aXNlIEZzdCBtYXRyaXgKCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiNQbG90IHBhaXJ3aXNlIEZzdCB2YWx1ZXMKYmN4Y2EgPC0gcm91bmQobWVhbihmc3QxNyRGc3RbZnN0MTckcG9wPT0iQkMxNy52cy5DQTE3Il0pLDQpCmJjeHB3IDwtIHJvdW5kKG1lYW4oZnN0MTckRnN0W2ZzdDE3JHBvcD09IkJDMTcudnMuUFdTMTciXSksNCkKY2F4cHcgPC0gcm91bmQobWVhbihmc3QxNyRGc3RbZnN0MTckcG9wPT0iQ0ExNy52cy5QV1MxNyJdKSw0KQpiY3h3YSA8LSByb3VuZChtZWFuKGZzdDE3JEZzdFtmc3QxNyRwb3A9PSJCQzE3LnZzLldBMTciXSksNCkKY2F4d2EgPC0gcm91bmQobWVhbihmc3QxNyRGc3RbZnN0MTckcG9wPT0iQ0ExNy52cy5XQTE3Il0pLDQpCmJjeHNzIDwtIHJvdW5kKG1lYW4oZnN0MTckRnN0W2ZzdDE3JHBvcD09IkJDMTcudnMuU1MxNyJdKSw0KQpiY3h0YiA8LSByb3VuZChtZWFuKGZzdDE3JEZzdFtmc3QxNyRwb3A9PSJCQzE3LnZzLlRCMTciXSksNCkKc3N4dGIgPC0gcm91bmQobWVhbihmc3QxNyRGc3RbZnN0MTckcG9wPT0iU1MxNy52cy5UQjE3Il0pLDQpCmNheHNzIDwtIHJvdW5kKG1lYW4oZnN0MTckRnN0W2ZzdDE3JHBvcD09IkNBMTcudnMuU1MxNyJdKSw0KQpwd3hzcyA8LSByb3VuZChtZWFuKGZzdDE3JEZzdFtmc3QxNyRwb3A9PSJQV1MxNy52cy5TUzE3Il0pLDQpCmNheHRiIDwtIHJvdW5kKG1lYW4oZnN0MTckRnN0W2ZzdDE3JHBvcD09IkNBMTcudnMuVEIxNyJdKSw0KQpwd3h0YiA8LSByb3VuZChtZWFuKGZzdDE3JEZzdFtmc3QxNyRwb3A9PSJQV1MxNy52cy5UQjE3Il0pLDQpCnB3eHdhIDwtIHJvdW5kKG1lYW4oZnN0MTckRnN0W2ZzdDE3JHBvcD09IlBXUzE3LnZzLldBMTciXSksNCkKc3N4d2EgPC0gcm91bmQobWVhbihmc3QxNyRGc3RbZnN0MTckcG9wPT0iU1MxNy52cy5XQTE3Il0pLDQpCnRieHdhIDwtIHJvdW5kKG1lYW4oZnN0MTckRnN0W2ZzdDE3JHBvcD09IlRCMTcudnMuV0ExNyJdKSw0KQoKZnN0X3ZlYyA8LSBjKDAscHd4dGIsc3N4dGIsYmN4dGIsdGJ4d2EsY2F4dGIsCiAgICAgICAgICAgICBwd3h0YiwwLHB3eHNzLGJjeHB3LHB3eHdhLGNheHB3LAogICAgICAgICAgICAgc3N4dGIscHd4c3MsMCxiY3hzcyxzc3h3YSxjYXhzcywKICAgICAgICAgICAgIGJjeHRiLGJjeHB3LGJjeHNzLDAsYmN4d2EsYmN4Y2EsCiAgICAgICAgICAgICB0Ynh3YSxwd3h3YSxzc3h3YSxiY3h3YSwwLGNheHdhLAogICAgICAgICAgICAgY2F4dGIsY2F4cHcsY2F4c3MsYmN4Y2EsY2F4d2EsMCkKCmZzdF9tYXQgPSBtYXRyaXgoZnN0X3ZlYywgbnJvdyA9IDYsIG5jb2wgPSA2KQpjb2xuYW1lcyhmc3RfbWF0KSA8LSBjKCJUQjE3IiwiUFdTMTciLCJTUzE3IiwiQkMxNyIsIldBMTciLCJDQTE3IikKcm93bmFtZXMoZnN0X21hdCkgPC0gYygiVEIxNyIsIlBXUzE3IiwiU1MxNyIsIkJDMTciLCJXQTE3IiwiQ0ExNyIpCgpmc3RfbWF0W2xvd2VyLnRyaShmc3RfbWF0LCBkaWFnID0gRildPC1OQQp3cml0ZS5jc3YoZnN0X21hdCwgIi4uL091dHB1dC9TRlMvRnN0X21hdHJpeF8yMDE3X2FsbC5jc3YiKQoKIyBNZWx0IHRoZSBjb3JyZWxhdGlvbiBtYXRyaXgKbWVsdGVkX2Nvcm1hdCA8LSBtZWx0KGZzdF9tYXQsIG5hLnJtID0gVFJVRSkKbWVsdGVkX2Nvcm1hdFttZWx0ZWRfY29ybWF0PT0wXTwtTkEKIyBIZWF0bWFwCm1lbHRlZF9jb3JtYXQkY29sb3I8LSJhIgptZWx0ZWRfY29ybWF0JGNvbG9yW21lbHRlZF9jb3JtYXQkdmFsdWU+PTAuMV08LSJiIgoKZ2dwbG90KGRhdGEgPSBtZWx0ZWRfY29ybWF0LCBhZXMoVmFyMiwgVmFyMSwgZmlsbCA9IHZhbHVlKSkrCiAgICBnZW9tX3RpbGUoY29sb3IgPSAid2hpdGUiKSsKICAgIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG9ycz1jKCJ3aGl0ZSIsICJibHVlIiksIGxpbWl0cz1jKDAsIChtYXgobWVsdGVkX2Nvcm1hdCR2YWx1ZSwgbmEucm09VCkrMC4wMDUpKSxuYS52YWx1ZT0iZ3JheTgwIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lPSJGc3QiKSsKICAgIHRoZW1lX21pbmltYWwoKSsgeGxhYigiIikreWxhYigiIikrCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDAsIHZqdXN0ID0gMCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMTIsIGhqdXN0ID0gMC41KSkrCiAgICB0aGVtZShheGlzLnRleHQueSA9IGVsZW1lbnRfdGV4dChzaXplID0gMTIpKSsKICAgIGNvb3JkX2ZpeGVkKCkrCiAgICBnZW9tX3RleHQoYWVzKFZhcjIsIFZhcjEsIGxhYmVsID0gdmFsdWUsIGNvbG9yPWNvbG9yKSwgIHNpemUgPSA1KSsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiYmxhY2siLCAid2hpdGUiKSwgZ3VpZGU9J25vbmUnKQpnZ3NhdmUoIi4uL091dHB1dC9TRlMvRnN0X21hdHJpeF8yMDE3X2FsbC5wbmciLCBoZWlnaHQgPSA2LCB3aWR0aCA9IDYsIGRwaT0xNTApCmBgYAohW10oLi4vT3V0cHV0L1NGUy9Gc3RfbWF0cml4XzIwMTdfYWxsLnBuZyl7d2lkdGg9NzUlfQoKIyMgRnN0IGNoYW5nZSBvdmVyIHRpbWUgYmV0d2VlbiBQV1MvU1MvVEIKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGV2YWw9RkFMU0V9Cgpjb21iPC1kYXRhLmZyYW1lKGE9YygiUFdTOTEiLCJQV1M5NiIsIlBXUzA3IiwiUFdTMTciLCJQV1M5NiIsIlBXUzA3IiwiUFdTMTciLCJTUzk2IiwiU1MwNiIsIlNTMTciKSxiPWMoIlRCOTEiLCJUQjk2IiwiVEIwNiIsIlRCMTciLCJTUzk2IiwiU1MwNiIsIlNTMTciLCJUQjk2IiwiVEIwNiIsIlRCMTciKSkgCgpmc3RzPC1kYXRhLmZyYW1lKCkKZm9yIChpIGluIDE6IG5yb3coY29tYikpewogICAgcG9wMTwtY29tYltpLDFdCiAgICBwb3AyPC1jb21iW2ksMl0KICAgIGRmPC1yZWFkLmRlbGltKHBhc3RlMCgiLi4vRGF0YS9uZXdfdmNmL2FuZ3NkL2Zyb21WQ0YvMkQvZnN0X2ZvbGRlZF8iLHBvcDEsIl8iLHBvcDIsIl81MGtXaW5kb3dfbWFmMDAiKSkKICAgIGNvbmFtZXM8LWNvbG5hbWVzKGRmKVsyOjRdCiAgICBjb2xuYW1lcyhkZilbNF08LSJGc3QiCiAgICBjb2xuYW1lcyhkZilbMTozXTwtY29uYW1lcwogICAgZGYkcG9wPC1wYXN0ZTAocG9wMSwiLnZzLiIscG9wMikKICAgIGRmJGNoPWFzLmludGVnZXIoZ3N1YigiY2hyIiwiIiwgZGYkY2hyKSkKICAgIGRmPC1kZltvcmRlcihkZiRjaCksXQogICAgZGYkbG9jPC0xOm5yb3coZGYpCiAgICBmc3RzPC1yYmluZChmc3RzLCBkZikKfQp3cml0ZS5jc3YoZnN0cywiLi4vT3V0cHV0L1NGUy9Gc3RfYmV0d2VlblBvcC5jc3YiKQoKcmU8LWFnZ3JlZ2F0ZShmc3RzJEZzdCwgYnk9bGlzdChmc3RzJHBvcCksIG1lYW4sIG5hLnJtPVQpCmNvbXBhPC1zdHJzcGxpdChyZSRHcm91cC4xLCBzcGxpdD0iLnZzLiIpCnJlJHBvcDE8LWxhcHBseShjb21wYSwgIltbIiwgMSkKcmUkcG9wMjwtbGFwcGx5KGNvbXBhLCAiW1siLCAyKQpyZSR5ZWFyIDwtIGFzLm51bWVyaWMoc3RyX2V4dHJhY3QocmUkcG9wMSwgIlswLTldKyIpKQpyZSR5ZWFyW3JlJHllYXI9PTd8cmUkeWVhcj09Nl08LTIwMDYKcmUkeWVhcltyZSR5ZWFyPT05MV08LTE5OTEKcmUkeWVhcltyZSR5ZWFyPT05Nl08LTE5OTYKcmUkeWVhcltyZSR5ZWFyPT0xN108LTIwMTcKcmUkcG9wMTwtc3RyX2V4dHJhY3QocmUkcG9wMSwgIlthQS16Wl0rIikKcmUkcG9wMjwtc3RyX2V4dHJhY3QocmUkcG9wMiwgIlthQS16Wl0rIikKcmUkcG9wczwtcGFzdGUwKHJlJHBvcDEsIi0iLHJlJHBvcDIpCgoKY29sb3JzMjwtYnJld2VyLnBhbChuPTgsICJTZXQzIikKIiM4REQzQzciICIjRkZGRkIzIiAiI0JFQkFEQSIgIiNGQjgwNzIiICIjODBCMUQzIiAiI0ZEQjQ2MiIgIiNCM0RFNjkiICIjRkNDREU1IgoKCmdncGxvdChyZSwgYWVzKHg9eWVhciwgeT14LCBjb2xvcj1wb3BzLCBncm91cD1wb3BzKSkrCiAgICBnZW9tX3BvaW50KHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksIHNpemU9MykrCiAgICBnZW9tX2xpbmUocG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSkrCiAgICB5bGFiKCJGc3QiKSt4bGFiKCJZZWFyIikrCiAgICB0aGVtZV9jbGFzc2ljKCkrdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9Y29sb3JzMltjKDQsMSwzKV0pCmdnc2F2ZSgiLi4vT3V0cHV0L1NGUy9Gc3Rfc2hpZnRfb3ZlclllYXJzXzNwb3BzLnBuZyIsIHdpZHRoID0gNSwgaGVpZ2h0ID0gMywgZHBpPTMwMCkKCmBgYAoKIVtdKC4uL091dHB1dC9TRlMvRnN0X3NoaWZ0X292ZXJZZWFyc18zcG9wcy5wbmcpe3dpZHRoPTUwJX0KCgoKPGJyPgo8YnI+CiAgCiMgVXNlIFBpeHkgdG8gY2FsY3VsYXRlIHBpCgojIyBTdGVwcwoKMS4gQ3JlYXRlIGFsbCBzaXRlcyAoaW52YXJpYW50KSB2Y2YgZmlsZXMgIAooc2VlIGludmFyaWFudFZDRl9QV1M5MS5zaCkKCmBgYHtiYXNoIGV2YWw9RkFMU0V9CiNVc2luZyBiY2Z0b29scyBtcGlsZXVwICgtciBpcyB0byBzcGVjaWZ5IGNocm9tb3NvbWUpCmJjZnRvb2xzIG1waWxldXAgLWYgPHJlZmVyZW5jZS5mYT4gLWIgPGJhbWxpc3QudHh0PiAtciA8WD4gfCBiY2Z0b29scyBjYWxsIC1tIC1PeiAtZiBHUSAtbyA8b3V0cHV0PgoKI0NyZWF0ZSBhIHNhbXBsZSBpZCBmaWxlIChyZXF1aXJlZCkKIyBBZGQgcG9wdWxhdGlvbiBpbmZvIHRvIHRoZSBzYW1wbGUgc2hlZXQKc2VkICdzLyQvXHRQV1M5MS8nIFBXUzkxLnR4dCA+cHdzOTFwb3AudHh0CgojY2hlY2sgdGhlIHNhbXBsZSBuYW1lcyBpbiB0aGUgdmNmIGZpbGUKYmNmdG9vbHMgcXVlcnkgLWwgUFdTOTFfY2gxLnZjZi5negojIHNvbWVob3csIF8gd2FzIHJlcGxhY2VkIGJ5IC4KYGBgCgoyLiAgUmVmb3JtYXQgdGhlIHNhbXBsZSBmaWxlICgnXycgd2FzIHJlcGxhY2VkIGJ5ICcuJyBpbiB0aGUgcHJvY2VzcyBvZiBtYWtpbmcgdmNmIGZpbGVzKSAgIAoKYGBge3IgZXZhbD1GQUxTRX0KcG9wczwtYygiUFdTOTEiLCJQV1M5NiIsIlBXUzA3IiwiUFdTMTciKQpmb3IgKGkgaW4gMTogbGVuZ3RoKHBvcHMpKXsKICAgIGRmPC1yZWFkLnRhYmxlKHBhc3RlMCgiLi4vRGF0YS9waXh5LyIscG9wc1tpXSwiLnR4dCIpKQogICAgZGYkVjE8LWdzdWIoIl8iLCIuIiwgZGYkVjEpCiAgICBkZiRWMjwtcG9wc1tpXQogICAgd3JpdGUudGFibGUoZGYsIHBhc3RlMCgiLi4vRGF0YS9waXh5LyIscG9wc1tpXSwicG9wLnR4dCIpLCBxdW90ZSA9IEYsIGNvbC5uYW1lcz1GLCByb3cubmFtZXMgPSBGLCBzZXA9Ilx0IikKfQoKcG9wczwtYygiVEI5MSIsIlRCOTYiLCJUQjA2IiwiVEIxNyIpCmZvciAoaSBpbiAxOiBsZW5ndGgocG9wcykpewogICAgZGY8LXJlYWQudGFibGUocGFzdGUwKCIuLi9EYXRhL3BpeHkvIixwb3BzW2ldLCIudHh0IikpCiAgICBkZiRWMTwtZ3N1YigiXyIsIi4iLCBkZiRWMSkKICAgIGRmJFYyPC1wb3BzW2ldCiAgICB3cml0ZS50YWJsZShkZiwgcGFzdGUwKCIuLi9EYXRhL3BpeHkvIixwb3BzW2ldLCIvIiAscG9wc1tpXSwicG9wLnR4dCIpLCBxdW90ZSA9IEYsIGNvbC5uYW1lcz1GLCByb3cubmFtZXMgPSBGLCBzZXA9Ilx0IikKfQoKcG9wczwtYygiU1M5NiIsIlNTMDYiLCJTUzE3IikKZm9yIChpIGluIDE6IGxlbmd0aChwb3BzKSl7CiAgICBkZjwtcmVhZC50YWJsZShwYXN0ZTAoIi4uL0RhdGEvcG9waW5mby8iLHBvcHNbaV0sIi50eHQiKSkKICAgIGRmJFYxPC1nc3ViKCJfIiwiLiIsIGRmJFYxKQogICAgZGYkVjI8LXBvcHNbaV0KICAgIHdyaXRlLnRhYmxlKGRmLCBwYXN0ZTAoIi4uL0RhdGEvcGl4eS8iLHBvcHNbaV0sIi8iICxwb3BzW2ldLCJwb3AudHh0IiksIHF1b3RlID0gRiwgY29sLm5hbWVzPUYsIHJvdy5uYW1lcyA9IEYsIHNlcD0iXHQiKQp9CnBvcHM8LWMoIkNBMTciLCJCQzE3IiwiV0ExNyIpCmZvciAoaSBpbiAxOiBsZW5ndGgocG9wcykpewogICAgZGY8LXJlYWQudGFibGUocGFzdGUwKCIuLi9EYXRhL3BvcGluZm8vIixwb3BzW2ldLCIudHh0IikpCiAgICBkZiRWMTwtZ3N1YigiXyIsIi4iLCBkZiRWMSkKICAgIGRmJFYyPC1wb3BzW2ldCiAgICB3cml0ZS50YWJsZShkZiwgcGFzdGUwKCIuLi9EYXRhL3BpeHkvIixwb3BzW2ldLCIvIiAscG9wc1tpXSwicG9wLnR4dCIpLCBxdW90ZSA9IEYsIGNvbC5uYW1lcz1GLCByb3cubmFtZXMgPSBGLCBzZXA9Ilx0IikKfQpgYGAKCjMuIFJ1biBQaXh5IChleGFtcGxlOiBQV1M5MSBDaHIxKQpgYGB7YmFzaCBldmFsPUZBTFNFfQojaW5kZXggdGhlIHZjZi5neiBmaWxlCnRhYml4IFBXUzkxX2NoMS52Y2YuZ3oKCiMgUnVuIFBpeHkgCiNmaXJzdCBhY3RpdmF0ZSB0aGUgY29uZGEgZW52IChweTM4KSAtcnVucyBvbiBvbGRlciBQeXRob24gKDw9My44KQpjb25kYSBhY3RpdmF0ZSBweTM4CmNkIH4vUHJvamVjdHMvUGFjSGVycmluZy9EYXRhL3BpeHkKcGl4eSAtLXN0YXRzIHBpIC0tdmNmIFBXUzkxX2NoMS52Y2YuZ3ogLS1wb3B1bGF0aW9ucyBwd3M5MXBvcC50eHQgLS13aW5kb3dfc2l6ZSAxMDAwMCAtLW5fY29yZSA4IC0tb3V0cHV0X3ByZWZpeCBQV1M5MV9jaDEKCmNvbmRhIGRlYWN0aXZhdGUKYGBgCgo0LiBTdW1tYXJpemUgdGhlIG91dHB1dCBmcm9tIFBpeHkgZm9yIFBXUzkxIENocjEgIAoKYGBge3Igd2FybmluZz1GQUxTRSxldmFsPUZBTFNFfQpwaXBpPC1yZWFkLnRhYmxlKCIuLi9EYXRhL3BpeHkvUFdTOTEvUFdTOTFfY2gxX3BpLnR4dCIsIGhlYWRlcj1UKQpnZ3Bsb3QocGlwaSwgYWVzKHg9d2luZG93X3Bvc18xLCB5PWF2Z19waSkpKwogICAgZ2VvbV9saW5lKGNvbG9yPWJsdSkreGxhYignJykreWxhYihleHByZXNzaW9uKCJtZWFuICIqcGkpKQpnZ3NhdmUoIi4uL091dHB1dC9TRlMvcGl4eV9waV9wd3M5MV9jaDFfbGluZS5wbmciLCB3aWR0aCA9IDYsIGhlaWdodCA9IDMuNSwgZHBpPTMwMCkKYGBgCiFbXSguLi9PdXRwdXQvU0ZTL3BpeHlfcGlfcHdzOTFfY2gxX2xpbmUucG5nKXt3aWR0aD03NSV9CgpgYGB7ciBldmFsPUZBTFNFLHdhcm5pbmc9RkFMU0UsIGVjaG89VFJVRX0KZ2dwbG90KHBpcGksIGFlcyh4PXdpbmRvd19wb3NfMSwgeT1hdmdfcGkpKSsKICAgIGdlb21fcG9pbnQoc2l6ZT0wLjMsIGNvbG9yPSJncmF5MjAiKQoKbWVhbihwaXBpJGF2Z19waSkKIyAwLjAwMjc4NDcxCgojd2VpZ2h0ZWQgbWVhbgpwaXBpJHBpX3N1bTwtcGlwaSRhdmdfcGkqcGlwaSRub19zaXRlcwpzdW0ocGlwaSRwaV9zdW0pL3N1bShwaXBpJG5vX3NpdGVzKQojIDAuMDAyNzc1NDY0CmBgYAoKIyMgQ29tcGFyZSDPgCBlc3RpbWF0ZWQgZnJvbSBBTkdTRCB2cy4gUGl4eQoKYGBge3IgZXZhbD1GQUxTRSx3YXJuaW5nPUZBTFNFLCBlY2hvPVRSVUV9CiNDb21wYXJlIHdpdGggdGhlIHBpIGVzdGltYXRlZCBmcm9tIEFOR1NEIFNGUyAKdGhldGE8LXJlYWQuZGVsaW0ocGFzdGUwKCcuLi9EYXRhL25ld192Y2YvYW5nc2QvZnJvbUJhbS91bmZvbGRlZC9QV1M5MV81MGt3aW5fMTBrc3RlcC5wZXN0UEcnKSkKdGhldGEkcGk8LXRoZXRhJHRQL3RoZXRhJG5TaXRlcwptZWFuKHRoZXRhJHBpW3RoZXRhJENocj09ImNocjEiXSkKIzAuMDAzODI2Mjk3CgojY2hyMSBjb21wYXJpc29uCmNoMTwtcGlwaVssYygiY2hyb21vc29tZSIsICJhdmdfcGkiKV0KY2gxJG1ldGhvZDwtIlBpeHkiCnRoZXRhMjwtdGhldGFbLGMoIkNociIsInBpIildCnRoZXRhMiRtZXRob2Q8LSJBTkdTRCIKY29sbmFtZXMoY2gxKVsxOjJdPC1jKCJDaHIiLCJwaSIpCmNoMTwtcmJpbmQoY2gxLHRoZXRhMikKCgpnZ3Bsb3QoY2gxLCBhZXMoeD1tZXRob2QsIHk9cGkpKSsKICAgIGdlb21fYm94cGxvdChhZXMobWlkZGxlPW1lYW4ocGkpLCBjb2xvcj1tZXRob2QpLG91dGxpZXIuYWxwaGEgPSAwLjIpKwogICAgdGhlbWVfY2xhc3NpYygpK3hsYWIoJycpK3lsYWIoZXhwcmVzc2lvbihwaSkpKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjMWY3OGI0IiwiI2ZiOWE5OSIpLCBndWlkZT0nbm9uZScpCmdnc2F2ZSgiLi4vT3V0cHV0L1NGUy9QaV9jb21wYXJpc29uX3BpeHkudnMuYW5nc2QucHdzOTEuY2gxLnBuZyIsIHdpZHRoPTQsIGhlaWdodD00LGRwaT0yMDAgKQpgYGAKIVtdKC4uL091dHB1dC9TRlMvUGlfY29tcGFyaXNvbl9waXh5LnZzLmFuZ3NkLnB3czkxLmNoMS5wbmcpe3dpZHRoPTUwJX0KCiMjIyBSdW4gUGl4eSBmb3IgYWxsIGNocm9tb3NvbWVzIGZvciBQV1MgCgpgYGB7YmFzaCBldmFsPUZBTFNFfQojaW5kZXggdmNmIGZpbGVzIGZvciBhbGwgY2hyb21vc29tZXMKZm9yIGYgaW4gKi52Y2YuZ3o7IGRvCmZpbGVuYW1lPSQoYmFzZW5hbWUgJGYpCnRhYml4ICRmIApkb25lCmBgYAoKCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0Usd2FybmluZz1GQUxTRX0KI2NyZWF0ZSBhIHNjcmlwdCB0byBydW4gcGl4eQpmb3IgKGogaW4gMTogbGVuZ3RoKHBvcHMpKXsKICAgIHNpbmsocGFzdGUwKCIuLi9EYXRhL3BpeHkvcnVucGl4eV8iLCBwb3BzW2pdLCIuc2giKSkKICAgIGNhdCgiIyEvYmluL2Jhc2hcblxuIikKICAgIGZvciAoaSBpbiAxOjI2KXsKICAgICAgICBjYXQocGFzdGUwKCJwaXh5IC0tc3RhdHMgcGkgLS12Y2YgIixwb3BzW2pdLCJfY2giLGksIi52Y2YuZ3ogLS1wb3B1bGF0aW9ucyAiLHBvcHNbal0sInBvcC50eHQgLS13aW5kb3dfc2l6ZSAxMDAwMCAtLW5fY29yZSA4IC0tb3V0cHV0X3ByZWZpeCAiLHBvcHNbal0sICJfY2giLGksICJcbiIpKQogICAgfQogICAgc2luayhOVUxMKQp9CmBgYAoKYGBge2Jhc2ggZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KI1J1biBwaXh5IApiYXNoIHJ1bnBpeHlfUFdTMTcuc2gKI3BpeHkgc2NyaXB0IGV4YW1wbGU6CnBpeHkgLS1zdGF0cyBwaSAtLXZjZiBQV1MxN19jaDI2LnZjZi5neiAtLXBvcHVsYXRpb25zIFBXUzE3cG9wLnR4dCAtLXdpbmRvd19zaXplIDEwMDAwIC0tbl9jb3JlIDggLS1vdXRwdXRfcHJlZml4IFBXUzE3X2NoMjYKYGBgCgoKIyMjIFBsb3QgdGhlIG91dHB1dHMgZnJvbSBQaXh5IGZvciBhbGwgUFdTIGdyb3VwcwpgYGB7ciAgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KI3JlYWQgdGhlIG91dHB1dCBmaWxlIGZvciBQV1M6CnBvcHM8LWMoIlBXUzkxIiwiUFdTOTYiLCJQV1MwNyIsIlBXUzE3IikKCmZvciAocCBpbiAxIDogbGVuZ3RoKHBvcHMpKXsKICAgIHBpeHk8LWRhdGEuZnJhbWUoKQogICAgZm9yIChpIGluIDE6MjYpewogICAgICAgIGRmPC1yZWFkLnRhYmxlKHBhc3RlMCgiLi4vRGF0YS9waXh5LyIscG9wc1twXSwiLyIscG9wc1twXSwiX2NoIixpLCJfcGkudHh0IiksIGhlYWRlcj1UKQogICAgICAgIGRmJG1ldGhvZDwtIlBpeHkiCiAgICAgICAgZGYkV2luQ2VudGVyPC1kZiR3aW5kb3dfcG9zXzItNTAwMAogICAgICAgIGRmPC1kZlssYygiY2hyb21vc29tZSIsIldpbkNlbnRlciIsImF2Z19waSIsIm1ldGhvZCIpXQogICAgICAgIGNvbG5hbWVzKGRmKVtjKDEsMyldPC1jKCJDaHIiLCJwaSIpCiAgICAgICAgcGl4eTwtcmJpbmQocGl4eSwgZGYpCiAgICB9CiAgICB3cml0ZS5jc3YocGl4eSwgcGFzdGUwKCIuLi9PdXRwdXQvUGkvIixwb3BzW3BdLCAiX1BpX3BpeHlfcGVyNTBrV2luZG93LmNzdiIpKQogICAgCiAgICAjQ29tcGFyZSB3aXRoIHRoZSBwaSBlc3RpbWF0ZWQgZnJvbSBBTkdTRCBTRlMgCiAgICB0aGV0YTwtcmVhZC5kZWxpbShwYXN0ZTAoJy4uL0RhdGEvbmV3X3ZjZi9hbmdzZC9mcm9tQmFtL3VuZm9sZGVkLycscG9wc1twXSwnXzUwa3dpbl8xMGtzdGVwLnBlc3RQRycpKQogICAgdGhldGEkcGk8LXRoZXRhJHRQL3RoZXRhJG5TaXRlcwogICAgdGhldGEkbWV0aG9kPC0iQU5HU0QiCiAgICBwaTwtcmJpbmQocGl4eSwgdGhldGFbLGMoIkNociIsIldpbkNlbnRlciIsInBpIiwibWV0aG9kIildKQoKICAgIHBpJENocjwtZmFjdG9yKHBpJENociwgbGV2ZWxzPXBhc3RlMCgiY2hyIiwxOjI2KSkKICAgIGdncGxvdChwaSwgYWVzKHg9Q2hyLCB5PXBpLCBjb2xvcj1tZXRob2QpKSsKICAgICAgICBnZW9tX2JveHBsb3QoYWVzKG1pZGRsZT1tZWFuKHBpKSksb3V0bGllci5hbHBoYSA9IDAuMiwgb3V0bGllci5zaXplID0gMC42KSsKICAgICAgICB0aGVtZV9jbGFzc2ljKCkrdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9NDUsIGhqdXN0ID0xKSkrCiAgICAgICAgeGxhYigiIikreWxhYihleHByZXNzaW9uKHBpKSkrZ2d0aXRsZShwb3BzW3BdKSsKICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWMoIiMxZjc4YjQiLCIjZmI5YTk5IikpCiAgICBnZ3NhdmUocGFzdGUwKCIuLi9PdXRwdXQvUGkvUGlfY29tcGFyaXNvbl9waXh5LnZzLmFuZ3NkLiIscG9wc1twXSwgIi5wbmciKSwgd2lkdGggPSAxMCwgaGVpZ2h0ID0gNSwgZHBpPTEwMCkKICAgIAogICAgIyBnZW5vbWUtd2lkZSBtZWFuIHBpIGNvbXBhcmlzb24KICAgIG1lYW5zIDwtIGFnZ3JlZ2F0ZShwaSB+ICBtZXRob2QsIHBpLCBtZWFuKQogICAgCiAgICBnZ3Bsb3QocGksIGFlcyh4PW1ldGhvZCwgeT1waSkpKwogICAgICAgIGdlb21fYm94cGxvdChhZXMoY29sb3I9bWV0aG9kKSwgb3V0bGllci5hbHBoYSA9IDAuMiwgb3V0bGllci5zaXplID0gMC42KSsKICAgICAgICB0aGVtZV9jbGFzc2ljKCkrIGdndGl0bGUocG9wc1twXSkrCiAgICAgICAgZ2VvbV9wb2ludChzdGF0ID0gInN1bW1hcnkiLCBmdW4gPSAibWVhbiIsIGNvbG9yPSJncmF5NDAiKSsKICAgICAgICAgeGxhYigiIikreWxhYihleHByZXNzaW9uKHBpKSkrCiAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjMWY3OGI0IiwiI2ZiOWE5OSIpLCBndWlkZT0nbm9uZScpKwogICAgICAgIGdlb21fdGV4dChkYXRhID0gbWVhbnMsIGFlcyhsYWJlbCA9IHJvdW5kKHBpLCBkaWdpdHM9NSksIHkgPSBwaSArIDAuMDIpLCBjb2xvcj0iZ3JheTQwIikKICAgIGdnc2F2ZShwYXN0ZTAoIi4uL091dHB1dC9QaS9QaV9jb21wYXJpc29uX3BpeHkudnMuYW5nc2RfbWVhbl8iLHBvcHNbcF0sIi5wbmciKSwgd2lkdGggPSAzLCBoZWlnaHQgPSAzLCBkcGk9MjAwKQp9CgpgYGAKCiFbXSguLi9PdXRwdXQvUGkvUGlfY29tcGFyaXNvbl9waXh5LnZzLmFuZ3NkX21lYW5fUFdTOTEucG5nKXt3aWR0aD0zMCV9ICFbUFdTOTFdKC4uL091dHB1dC9QaS9QaV9jb21wYXJpc29uX3BpeHkudnMuYW5nc2RfUFdTOTEucG5nKXt3aWR0aD02MCV9IAoKIVtQV1MwN10oLi4vT3V0cHV0L1BpL1BpX2NvbXBhcmlzb25fcGl4eS52cy5hbmdzZF9tZWFuX1BXUzA3LnBuZyl7d2lkdGg9MzAlfSFbXSguLi9PdXRwdXQvUGkvUGlfY29tcGFyaXNvbl9waXh5LnZzLmFuZ3NkLlBXUzA3LnBuZyl7d2lkdGg9NjAlfSAgCgohW1BXUzE3XSguLi9PdXRwdXQvUGkvUGlfY29tcGFyaXNvbl9waXh5LnZzLmFuZ3NkX21lYW5fUFdTMTcucG5nKXt3aWR0aD0zMCV9IVtdKC4uL091dHB1dC9QaS9QaV9jb21wYXJpc29uX3BpeHkudnMuYW5nc2QuUFdTMTcucG5nKXt3aWR0aD02MCV9ICAKCi0gKipQaXh5IGVzdGltYXRlcyBoYXZlIG1vcmUgdmFyaWFiaWxpdHkqKgotICoqUGl4eSBlc2l0bWF0ZXMgYXJlIHNsaWdodGx5IGxvd2VyIHRoYW4gQU5TR0QgZXN0aWFtdGVzKioKCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgQXNzZXNzIHRoZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIEFOR1NEIGFuZCBQaXh5CnBvcHM8LWMoIlBXUzkxIiwiUFdTOTYiLCJQV1MwNyIsIlBXUzE3IikKZGlmZjwtZGF0YS5mcmFtZShwb3A9cG9wcykKZm9yIChwIGluIDEgOiBsZW5ndGgocG9wcykpewogICAgcGl4eTwtZGF0YS5mcmFtZSgpCiAgICBmb3IgKGkgaW4gMToyNil7CiAgICAgICAgZGY8LXJlYWQudGFibGUocGFzdGUwKCIuLi9EYXRhL3BpeHkvIixwb3BzW3BdLCIvIixwb3BzW3BdLCJfY2giLGksIl9waS50eHQiKSwgaGVhZGVyPVQpCiAgICAgICAgZGYkbWV0aG9kPC0iUGl4eSIKICAgICAgICBkZiRXaW5DZW50ZXI8LWRmJHdpbmRvd19wb3NfMi01MDAwCiAgICAgICAgZGY8LWRmWyxjKCJjaHJvbW9zb21lIiwiV2luQ2VudGVyIiwiYXZnX3BpIiwibWV0aG9kIildCiAgICAgICAgY29sbmFtZXMoZGYpW2MoMSwzKV08LWMoIkNociIsInBpIikKICAgICAgICBwaXh5PC1yYmluZChwaXh5LCBkZikKICAgIH0KICAgICNtZWFuLnBpeHk8LWFnZ3JlZ2F0ZShwaXh5JHBpLCBieT1saXN0KHBpeHkkQ2hyKSwgbWVhbiwgbmEucm09VCkKICAgIAogICAgI1BpIGVzdGltYXRlZCBmcm9tIEFOR1NEIFNGUyAKICAgIHRoZXRhPC1yZWFkLmRlbGltKHBhc3RlMCgnLi4vRGF0YS9uZXdfdmNmL2FuZ3NkL2Zyb21CYW0vdW5mb2xkZWQvJyxwb3BzW3BdLCdfNTBrd2luXzEwa3N0ZXAucGVzdFBHJykpCiAgICB0aGV0YSRwaTwtdGhldGEkdFAvdGhldGEkblNpdGVzCiAgICB0aGV0YSRtZXRob2Q8LSJBTkdTRCIKICAgIHBpPC1yYmluZChwaXh5LCB0aGV0YVssYygiQ2hyIiwiV2luQ2VudGVyIiwicGkiLCJtZXRob2QiKV0pCgogICAgbWVhbnM8LWFnZ3JlZ2F0ZShwaSRwaSwgYnk9bGlzdChwaSRtZXRob2QpLCBtZWFuLCBuYS5ybT1UKQogICAgCiAgICAjZGlmZmVyZW5jZXMgaW4gcGkgZXN0aW1hdGVzCiAgICAKICAgIGRpZmYkcHJvcC5kaWZmZXJlbmNlW3BdPC1tZWFucyR4W21lYW5zJEdyb3VwLjE9PSJBTkdTRCJdL21lYW5zJHhbbWVhbnMkR3JvdXAuMT09IlBpeHkiXQp9CgoKa25pdHI6OmthYmxlKGRpZmYpCgpgYGAKCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpwb3BzPC1jKCJQV1M5MSIsIlBXUzk2IiwiUFdTMDciLCJQV1MxNyIpClBpPC1kYXRhLmZyYW1lKCkKZm9yIChpIGluIDE6bGVuZ3RoKHBvcHMpKXsKICAgICNwaXh5CiAgICBwaTwtcmVhZC5jc3YocGFzdGUwKCIuLi9PdXRwdXQvUGkvIixwb3BzW2ldLCAiX1BpX3BpeHlfcGVyNTBrV2luZG93LmNzdiIpLCByb3cubmFtZXMgPTEgKQogICAgcGkkQ2hyPC1mYWN0b3IocGkkQ2hyLCBsZXZlbHM9cGFzdGUwKCJjaHIiLDE6MjYpKQogICAgcGkkcG9wPC1wb3BzW2ldCiAgICBQaTwtcmJpbmQoUGkscGkpCiAgICAKICAgIHRoZXRhPC1yZWFkLmRlbGltKHBhc3RlMCgnLi4vRGF0YS9uZXdfdmNmL2FuZ3NkL2Zyb21CYW0vdW5mb2xkZWQvJyxwb3BzW2ldLCdfNTBrd2luXzEwa3N0ZXAucGVzdFBHJykpCiAgICB0aGV0YSRwaTwtdGhldGEkdFAvdGhldGEkblNpdGVzCiAgICB0aGV0YSRwb3A8LXBvcHNbaV0KICAgIHRoZXRhJG1ldGhvZDwtIkFOR1NEIgogICAgdGhldGE8LXRoZXRhWyxjKCJDaHIiLCAiV2luQ2VudGVyIiwicGkiLCJtZXRob2QiLCJwb3AiKV0gICAgCiAgICBQaTwtcmJpbmQoUGksIHRoZXRhKQp9CgpQaSRwb3A8LWZhY3RvcihQaSRwb3AsIGxldmVscz1wb3BzKQoKIyBnZW5vbWUtd2lkZSBtZWFuIHBpIGNvbXBhcmlzb24KbWVhbnMgPC0gYWdncmVnYXRlKFBpJHBpLCBieT1saXN0KFBpJG1ldGhvZCwgUGkkcG9wKSwgbWVhbiwgbmEucm09VCkKY29sbmFtZXMobWVhbnMpPC1jKCJtZXRob2QiLCJwb3AiLCAicGkiKQpnZ3Bsb3QoUGksIGFlcyh4PXBvcCwgeT1waSwgY29sb3I9bWV0aG9kKSkrCiAgICBnZW9tX2JveHBsb3QocG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGg9MC44KSwgIG91dGxpZXIuYWxwaGEgPSAwLjIsIG91dGxpZXIuc2l6ZSA9IDAuNikrCiAgICB0aGVtZV9jbGFzc2ljKCkgKyB5bGltKDAsMC4wNDUpKwogICAgc3RhdF9zdW1tYXJ5KGZ1biA9ICJtZWFuIiwgZ2VvbSA9ICJwb2ludCIsIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoPTAuOCksIHNoYXBlPTE2KSsKICAgIHhsYWIoIiIpK3lsYWIoZXhwcmVzc2lvbihwaSkpKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjMWY3OGI0IiwiI2ZiOWE5OSIpKSsKICAgIGFubm90YXRlKGdlb209InRleHQiLCB4PWFzLnZlY3RvcihzYXBwbHkoMTo0LCBmdW5jdGlvbih4KSBjKHgtLjIsIHgrLjIpKSksIHk9cmVwKGMoMC4wMTgsIDAuMDIpLHRpbWVzPTQpLCBsYWJlbD1yb3VuZChtZWFucyRwaSwgZGlnaXRzPTUpLCBzaXplPTIuNSkKCmdnc2F2ZShwYXN0ZTAoIi4uL091dHB1dC9QaS9QaV9jb21wYXJpc29uX3BpeHkudnMuYW5nc2RfbWVhbl9QV1MucG5nIiksIHdpZHRoID02LCBoZWlnaHQgPSAzLCBkcGk9MzAwKQoKZ2dwbG90KFBpLCBhZXMoeD1wb3AsIHk9cGksIGNvbG9yPW1ldGhvZCkpKwogICAgZ2VvbV9ib3hwbG90KHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoPTAuOCksICBvdXRsaWVyLmFscGhhID0gMC4yLCBvdXRsaWVyLnNpemUgPSAwLjYpKwogICAgdGhlbWVfY2xhc3NpYygpICt5bGltKDAsMC4wMTUpKwogICAgc3RhdF9zdW1tYXJ5KGZ1biA9ICJtZWFuIiwgZ2VvbSA9ICJwb2ludCIsIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoPTAuOCksIHNoYXBlPTE2KSsKICAgIHhsYWIoIiIpK3lsYWIoZXhwcmVzc2lvbihwaSkpKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCIjMWY3OGI0IiwiI2ZiOWE5OSIpKQogICAgYW5ub3RhdGUoZ2VvbT0idGV4dCIsIHg9YXMudmVjdG9yKHNhcHBseSgxOjQsIGZ1bmN0aW9uKHgpIGMoeC0uMiwgeCsuMikpKSwgeT1yZXAoYygwLjAxOCwgMC4wMiksdGltZXM9NCksIGxhYmVsPXJvdW5kKG1lYW5zJHBpLCBkaWdpdHM9NSksIHNpemU9MikKCmdnc2F2ZShwYXN0ZTAoIi4uL091dHB1dC9QaS9QaV9jb21wYXJpc29uX3BpeHkudnMuYW5nc2RfbWVhbl9QV1Nfem9vbWVkLnBuZyIpLCB3aWR0aCA9Ni43LCBoZWlnaHQgPSAzLCBkcGk9MzAwKQoKCmBgYAoKCgoKCiMjIyBDb21wYXJlIGFjcm9zcyB5ZWFycyAtUFdTCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9Cgpwb3BzPC1jKCJQV1M5MSIsIlBXUzk2IiwiUFdTMDciLCJQV1MxNyIpClBpPC1kYXRhLmZyYW1lKCkKZm9yIChpIGluIDE6bGVuZ3RoKHBvcHMpKXsKICAgIHBpPC1yZWFkLmNzdihwYXN0ZTAoIi4uL091dHB1dC9QaS8iLHBvcHNbaV0sICJfUGlfcGl4eV9wZXI1MGtXaW5kb3cuY3N2IiksIHJvdy5uYW1lcyA9MSApCiAgICBwaSRDaHI8LWZhY3RvcihwaSRDaHIsIGxldmVscz1wYXN0ZTAoImNociIsMToyNikpCiAgICBwaSRwb3A8LXBvcHNbaV0KICAgIFBpPC1yYmluZChQaSxwaSkKfQoKUGkkcG9wPC1mYWN0b3IoUGkkcG9wLCBsZXZlbHM9cG9wcykKCm1lYW5zIDwtIGFnZ3JlZ2F0ZShwaSB+IHBvcCxQaSwgbWVhbikKY29sbmFtZXMobWVhbnMpPC1jKCJtZXRob2QiLCJwb3AiLCAicGkiKQpnZ3Bsb3QoUGksIGFlcyh4PXBvcCwgeT1waSwgY29sb3I9cG9wKSkrCiAgICAgICAgZ2VvbV9ib3hwbG90KGFlcyhjb2xvcj1wb3ApLCBvdXRsaWVyLmFscGhhID0gMC4yLCBvdXRsaWVyLnNpemUgPSAwLjYpKwogICAgICAgIHRoZW1lX2NsYXNzaWMoKSsgZ2d0aXRsZSgiUFdTIikrCiAgICAgICAgZ2VvbV9wb2ludChzdGF0ID0gInN1bW1hcnkiLCBmdW4gPSAibWVhbiIsIGNvbG9yPSJncmF5NDAiKSsKICAgICAgICAgeGxhYigiIikreWxhYihleHByZXNzaW9uKHBpKSkrCiAgICAgICAgZ2VvbV90ZXh0KGRhdGEgPSBtZWFucywgYWVzKGxhYmVsID0gcm91bmQocGksIGRpZ2l0cz01KSwgeSA9IHBpICsgMC4wMiksIGNvbG9yPSJncmF5NDAiKQpnZ3NhdmUocGFzdGUwKCIuLi9PdXRwdXQvUGkvUGlfcGl4eV9tZWFuLiIscG9wc1tpXSwiLnBuZyIpLCB3aWR0aCA9IDQuNSwgaGVpZ2h0ID0gMywgZHBpPTIwMCkKYGBgCgohW10oLi4vT3V0cHV0L1BpL1BpX3BpeHlfbWVhbi5QV1MucG5nKXt3aWR0aD02MCV9CgoKYGBge3IgIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiNyZWFkIHRoZSBvdXRwdXQgZmlsZSBmb3IgZWFjaCBwb3BzOgpwb3BzPC1jKCJUQjkxIiwiVEI5NiIsIlRCMDYiLCJUQjE3IikKCmZvciAocCBpbiAxIDogbGVuZ3RoKHBvcHMpKXsKICAgIHBpeHk8LWRhdGEuZnJhbWUoKQogICAgZm9yIChpIGluIDE6MjYpewogICAgICAgIGRmPC1yZWFkLnRhYmxlKHBhc3RlMCgiLi4vRGF0YS9waXh5LyIscG9wc1twXSwiLyIscG9wc1twXSwiX2NoIixpLCJfcGkudHh0IiksIGhlYWRlcj1UKQogICAgICAgIGRmJG1ldGhvZDwtIlBpeHkiCiAgICAgICAgZGYkV2luQ2VudGVyPC1kZiR3aW5kb3dfcG9zXzItNTAwMAogICAgICAgIGRmPC1kZlssYygiY2hyb21vc29tZSIsIldpbkNlbnRlciIsImF2Z19waSIsIm1ldGhvZCIpXQogICAgICAgIGNvbG5hbWVzKGRmKVtjKDEsMyldPC1jKCJDaHIiLCJwaSIpCiAgICAgICAgcGl4eTwtcmJpbmQocGl4eSwgZGYpCiAgICB9CiAgICB3cml0ZS5jc3YocGl4eSwgcGFzdGUwKCIuLi9PdXRwdXQvUGkvIixwb3BzW3BdLCAiX1BpX3BpeHlfcGVyNTBrV2luZG93LmNzdiIpKQp9CgpQaTwtZGF0YS5mcmFtZSgpCmZvciAoaSBpbiAxOmxlbmd0aChwb3BzKSl7CiAgICBwaTwtcmVhZC5jc3YocGFzdGUwKCIuLi9PdXRwdXQvUGkvIixwb3BzW2ldLCAiX1BpX3BpeHlfcGVyNTBrV2luZG93LmNzdiIpLCByb3cubmFtZXMgPTEgKQoKICAgIHBpJENocjwtZmFjdG9yKHBpJENociwgbGV2ZWxzPXBhc3RlMCgiY2hyIiwxOjI2KSkKICAgIGdncGxvdChwaSwgYWVzKHg9Q2hyLCB5PXBpKSkrCiAgICAgICAgZ2VvbV9ib3hwbG90KGFlcyhtaWRkbGU9bWVhbihwaSkpLG91dGxpZXIuYWxwaGEgPSAwLjIsIG91dGxpZXIuc2l6ZSA9IDAuNixjb2xvcj0iIzFmNzhiNCIpKwogICAgICAgIHRoZW1lX2NsYXNzaWMoKSt0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3QgPTEpKSsKICAgICAgICB4bGFiKCIiKSt5bGFiKGV4cHJlc3Npb24ocGkpKStnZ3RpdGxlKHBvcHNbaV0pCiAgICBnZ3NhdmUocGFzdGUwKCIuLi9PdXRwdXQvUGkvUGlfcGl4eS5wZXJDaHJvbS4iLHBvcHNbaV0sICIucG5nIiksIHdpZHRoID0gOC41LCBoZWlnaHQgPSA1LCBkcGk9MzAwKQogICAgCiAgICBwaSRwb3A8LXBvcHNbaV0KICAgIFBpPC1yYmluZChQaSxwaSkKfQoKUGkkcG9wPC1mYWN0b3IoUGkkcG9wLCBsZXZlbHM9cG9wcykKbWVhbnMgPC0gYWdncmVnYXRlKHBpIH4gcG9wLFBpLCBtZWFuKQpnZ3Bsb3QoUGksIGFlcyh4PXBvcCwgeT1waSwgY29sb3I9cG9wKSkrCiAgICAgICAgZ2VvbV9ib3hwbG90KGFlcyhjb2xvcj1wb3ApLCBvdXRsaWVyLmFscGhhID0gMC4yLCBvdXRsaWVyLnNpemUgPSAwLjYpKwogICAgICAgIHRoZW1lX2NsYXNzaWMoKSsgZ2d0aXRsZSgiVEIiKSsKICAgICAgICBnZW9tX3BvaW50KHN0YXQgPSAic3VtbWFyeSIsIGZ1biA9ICJtZWFuIiwgY29sb3I9ImdyYXk0MCIpKwogICAgICAgICB4bGFiKCIiKSt5bGFiKGV4cHJlc3Npb24ocGkpKSsKICAgICAgICBnZW9tX3RleHQoZGF0YSA9IG1lYW5zLCBhZXMobGFiZWwgPSByb3VuZChwaSwgZGlnaXRzPTUpLCB5ID0gcGkgKyAwLjAyKSwgY29sb3I9ImdyYXk0MCIpCmdnc2F2ZShwYXN0ZTAoIi4uL091dHB1dC9QaS9QaV9waXh5X21lYW4uVEIucG5nIiksIHdpZHRoID0gNC41LCBoZWlnaHQgPSAzLCBkcGk9MjAwKQpgYGAKCiFbXSguLi9PdXRwdXQvUGkvUGlfcGl4eV9tZWFuLlRCLnBuZyl7d2lkdGg9NzAlfQoKCmBgYHtyICBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBldmFsPUZBTFNFfQojcmVhZCB0aGUgb3V0cHV0IGZpbGUgZm9yIGVhY2ggU1MgcG9wOgpwb3BzPC1jKCJTUzk2IiwiU1MwNiIsIlNTMTciKQpmb3IgKHAgaW4gMSA6IGxlbmd0aChwb3BzKSl7CiAgICBwaXh5PC1kYXRhLmZyYW1lKCkKICAgIGZvciAoaSBpbiAxOjI2KXsKICAgICAgICBkZjwtcmVhZC50YWJsZShwYXN0ZTAoIi4uL0RhdGEvcGl4eS8iLHBvcHNbcF0sIi8iLHBvcHNbcF0sIl9jaCIsaSwiX3BpLnR4dCIpLCBoZWFkZXI9VCkKICAgICAgICBkZiRtZXRob2Q8LSJQaXh5IgogICAgICAgIGRmJFdpbkNlbnRlcjwtZGYkd2luZG93X3Bvc18yLTUwMDAKICAgICAgICBkZjwtZGZbLGMoImNocm9tb3NvbWUiLCJXaW5DZW50ZXIiLCJhdmdfcGkiLCJtZXRob2QiKV0KICAgICAgICBjb2xuYW1lcyhkZilbYygxLDMpXTwtYygiQ2hyIiwicGkiKQogICAgICAgIHBpeHk8LXJiaW5kKHBpeHksIGRmKQogICAgfQogICAgd3JpdGUuY3N2KHBpeHksIHBhc3RlMCgiLi4vT3V0cHV0L1BpLyIscG9wc1twXSwgIl9QaV9waXh5X3BlcjUwa1dpbmRvdy5jc3YiKSkKfQoKUGk8LWRhdGEuZnJhbWUoKQpmb3IgKGkgaW4gMTpsZW5ndGgocG9wcykpewogICAgcGk8LXJlYWQuY3N2KHBhc3RlMCgiLi4vT3V0cHV0L1BpLyIscG9wc1tpXSwgIl9QaV9waXh5X3BlcjUwa1dpbmRvdy5jc3YiKSwgcm93Lm5hbWVzID0xICkKICAgIHBpJENocjwtZmFjdG9yKHBpJENociwgbGV2ZWxzPXBhc3RlMCgiY2hyIiwxOjI2KSkKICAgIGdncGxvdChwaSwgYWVzKHg9Q2hyLCB5PXBpKSkrCiAgICAgICAgZ2VvbV9ib3hwbG90KGFlcyhtaWRkbGU9bWVhbihwaSkpLG91dGxpZXIuYWxwaGEgPSAwLjIsIG91dGxpZXIuc2l6ZSA9IDAuNixjb2xvcj0iIzFmNzhiNCIpKwogICAgICAgIHRoZW1lX2NsYXNzaWMoKSt0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3QgPTEpKSsKICAgICAgICB4bGFiKCIiKSt5bGFiKGV4cHJlc3Npb24ocGkpKStnZ3RpdGxlKHBvcHNbaV0pCiAgICBnZ3NhdmUocGFzdGUwKCIuLi9PdXRwdXQvUGkvUGlfcGl4eS5wZXJDaHJvbS4iLHBvcHNbaV0sICIucG5nIiksIHdpZHRoID0gOC41LCBoZWlnaHQgPSA1LCBkcGk9MzAwKQogICAgCiAgICBwaSRwb3A8LXBvcHNbaV0KICAgIFBpPC1yYmluZChQaSxwaSkKfQoKUGkkcG9wPC1mYWN0b3IoUGkkcG9wLCBsZXZlbHM9cG9wcykKbWVhbnMgPC0gYWdncmVnYXRlKHBpIH4gcG9wLFBpLCBtZWFuKQoKZ2dwbG90KFBpLCBhZXMoeD1wb3AsIHk9cGksIGNvbG9yPXBvcCkpKwogICAgICAgIGdlb21fYm94cGxvdChhZXMoY29sb3I9cG9wKSwgb3V0bGllci5hbHBoYSA9IDAuMiwgb3V0bGllci5zaXplID0gMC42KSsKICAgICAgICB0aGVtZV9jbGFzc2ljKCkrCiAgICAgICAgZ2VvbV9wb2ludChzdGF0ID0gInN1bW1hcnkiLCBmdW4gPSAibWVhbiIsIGNvbG9yPSJncmF5NDAiKSsKICAgICAgICAgeGxhYigiIikreWxhYihleHByZXNzaW9uKHBpKSkrZ2d0aXRsZSgiU1MiKSsKICAgICAgICBnZW9tX3RleHQoZGF0YSA9IG1lYW5zLCBhZXMobGFiZWwgPSByb3VuZChwaSwgZGlnaXRzPTUpLCB5ID0gcGkgKyAwLjAyKSwgY29sb3I9ImdyYXk0MCIpCmdnc2F2ZShwYXN0ZTAoIi4uL091dHB1dC9QaS9QaV9waXh5X21lYW4uU1MucG5nIiksIHdpZHRoID0gNC41LCBoZWlnaHQgPSAzLCBkcGk9MjAwKQpgYGAKCiFbXSguLi9PdXRwdXQvUGkvUGlfcGl4eV9tZWFuLlNTLnBuZyl7d2lkdGg9NjAlfQoKCmBgYHtyICBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBldmFsPUZBTFNFfQogCiNyZWFkIHRoZSBvdXRwdXQgZmlsZSBmb3IgZWFjaCBwb3BzOgpwb3BzPC1jKCJCQzE3IiwiQ0ExNyIsIldBMTciKQpmb3IgKHAgaW4gMSA6IGxlbmd0aChwb3BzKSl7CiAgICBwaXh5PC1kYXRhLmZyYW1lKCkKICAgIGZvciAoaSBpbiAxOjI2KXsKICAgICAgICBkZjwtcmVhZC50YWJsZShwYXN0ZTAoIi4uL0RhdGEvcGl4eS8iLHBvcHNbcF0sIi8iLHBvcHNbcF0sIl9jaCIsaSwiX3BpLnR4dCIpLCBoZWFkZXI9VCkKICAgICAgICBkZiRtZXRob2Q8LSJQaXh5IgogICAgICAgIGRmJFdpbkNlbnRlcjwtZGYkd2luZG93X3Bvc18yLTUwMDAKICAgICAgICBkZjwtZGZbLGMoImNocm9tb3NvbWUiLCJXaW5DZW50ZXIiLCJhdmdfcGkiLCJtZXRob2QiKV0KICAgICAgICBjb2xuYW1lcyhkZilbYygxLDMpXTwtYygiQ2hyIiwicGkiKQogICAgICAgIHBpeHk8LXJiaW5kKHBpeHksIGRmKQogICAgfQogICAgd3JpdGUuY3N2KHBpeHksIHBhc3RlMCgiLi4vT3V0cHV0L1BpLyIscG9wc1twXSwgIl9QaV9waXh5X3BlcjUwa1dpbmRvdy5jc3YiKSkKfQoKUGk8LWRhdGEuZnJhbWUoKQpmb3IgKGkgaW4gMTpsZW5ndGgocG9wcykpewogICAgcGk8LXJlYWQuY3N2KHBhc3RlMCgiLi4vT3V0cHV0L1BpLyIscG9wc1tpXSwgIl9QaV9waXh5X3BlcjUwa1dpbmRvdy5jc3YiKSwgcm93Lm5hbWVzID0xICkKICAgIHBpJENocjwtZmFjdG9yKHBpJENociwgbGV2ZWxzPXBhc3RlMCgiY2hyIiwxOjI2KSkKICAgIGdncGxvdChwaSwgYWVzKHg9Q2hyLCB5PXBpKSkrCiAgICAgICAgZ2VvbV9ib3hwbG90KGFlcyhtaWRkbGU9bWVhbihwaSkpLG91dGxpZXIuYWxwaGEgPSAwLjIsIG91dGxpZXIuc2l6ZSA9IDAuNixjb2xvcj0iIzFmNzhiNCIpKwogICAgICAgIHRoZW1lX2NsYXNzaWMoKSt0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3QgPTEpKSsKICAgICAgICB4bGFiKCIiKSt5bGFiKGV4cHJlc3Npb24ocGkpKStnZ3RpdGxlKHBvcHNbaV0pCiAgICBnZ3NhdmUocGFzdGUwKCIuLi9PdXRwdXQvUGkvUGlfcGl4eS5wZXJDaHJvbS4iLHBvcHNbaV0sICIucG5nIiksIHdpZHRoID0gOC41LCBoZWlnaHQgPSA1LCBkcGk9MzAwKQogICAgCiAgICBwaSRwb3A8LXBvcHNbaV0KICAgIFBpPC1yYmluZChQaSxwaSkKfQoKUGkkcG9wPC1mYWN0b3IoUGkkcG9wLCBsZXZlbHM9cG9wcykKbWVhbnMgPC0gYWdncmVnYXRlKHBpIH4gcG9wLFBpLCBtZWFuKQoKZ2dwbG90KFBpLCBhZXMoeD1wb3AsIHk9cGksIGNvbG9yPXBvcCkpKwogICAgICAgIGdlb21fYm94cGxvdChhZXMoY29sb3I9cG9wKSwgb3V0bGllci5hbHBoYSA9IDAuMiwgb3V0bGllci5zaXplID0gMC42KSsKICAgICAgICB0aGVtZV9jbGFzc2ljKCkrCiAgICAgICAgZ2VvbV9wb2ludChzdGF0ID0gInN1bW1hcnkiLCBmdW4gPSAibWVhbiIsIGNvbG9yPSJncmF5NDAiKSsKICAgICAgICAgeGxhYigiIikreWxhYihleHByZXNzaW9uKHBpKSkrCiAgICAgICAgZ2VvbV90ZXh0KGRhdGEgPSBtZWFucywgYWVzKGxhYmVsID0gcm91bmQocGksIGRpZ2l0cz01KSwgeSA9IHBpICsgMC4wMiksIGNvbG9yPSJncmF5NDAiKQojZ2dzYXZlKHBhc3RlMCgiLi4vT3V0cHV0L1BpL1BpX3BpeHlfbWVhbi5DQS5CQy5XQS5wbmciKSwgd2lkdGggPSA0LjUsIGhlaWdodCA9IDMsIGRwaT0yMDApCmBgYAoKYGBge3IgIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcG9wczwtYygiUFdTOTEiLCJQV1M5NiIsIlBXUzA3IiwiUFdTMTciLCJUQjkxIiwiVEI5NiIsIlRCMDYiLCJUQjE3IiwiU1M5NiIsIlNTMDYiLCJTUzE3IikKeWVhcjwtYygxOTkxLDE5OTYsMjAwNywyMDE3LDE5OTEsMTk5NiwyMDA2LDIwMTcsMTk5NiwyMDA2LDIwMTcpCm1lYW5QaTwtZGF0YS5mcmFtZShwb3AueXI9cG9wcywgeWVhcj15ZWFyKQpmb3IgKGkgaW4gMTpsZW5ndGgocG9wcykpewogICAgZGY8LXJlYWQuY3N2KHBhc3RlMCgiLi4vT3V0cHV0L1BpLyIscG9wc1tpXSwgIl9QaV9waXh5X3BlcjUwa1dpbmRvdy5jc3YiKSwgcm93Lm5hbWVzID0xICkKICAgIG1lYW5QaSRtZWFuW2ldPC1tZWFuKGRmJHBpLCBuYS5ybT1UKQogICAgbWVhblBpJHBvcFtpXTwtZ3N1YigiXFxkLisiLCIiLHBvcHNbaV0pCn0KCgpnZ3Bsb3QobWVhblBpLCBhZXMoeD15ZWFyLCB5PW1lYW4sIGNvbG9yPXBvcCkpKwogICAgZ2VvbV9wb2ludChzaXplPTMpKwogICAgZ2VvbV9saW5lKCkrCiAgICB4bGFiKCIiKSt5bGFiKHBhc3RlMCgiTWVhbiAiLGV4cHJlc3Npb24ocGkpKSkrCiAgICB0aGVtZV9saW5lZHJhdygpKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jb2xzW2MoMiwxLDUpXSkKZ2dzYXZlKCIuLi9PdXRwdXQvUGkvUGlfb3ZlclllYXJzLlBXUy5UQi5TUy5wbmciLCB3aWR0aCA9IDYsIGhlaWdodCA9IDQsIGRwaT0zMDApCgpgYGAKIVtdKC4uL091dHB1dC9QaS9QaV9vdmVyWWVhcnMuUFdTLlRCLlNTLnBuZyl7d2lkdGg9NjUlfQoKCmBgYHtyICBlY2hvPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBldmFsPUZBTFNFfQoKcG9wczwtYygiVEI5MSIsIlRCOTYiLCJUQjA2IiwiVEIxNyIsIlBXUzkxIiwiUFdTOTYiLCJQV1MwNyIsIlBXUzE3IiwiU1M5NiIsIlNTMDYiLCJTUzE3IiwiQkMxNyIsIldBMTciLCJDQTE3IikKeWVhcjwtYygxOTkxLDE5OTYsMjAwNiwyMDE3LDE5OTEsMTk5NiwyMDA3LDIwMTcsMTk5NiwyMDA2LDIwMTcsMjAxNywyMDE3LDIwMTcpCm1lYW5QaTwtZGF0YS5mcmFtZShwb3AueXI9cG9wcywgeWVhcj15ZWFyKQpmb3IgKGkgaW4gMTpsZW5ndGgocG9wcykpewogICAgZGY8LXJlYWQuY3N2KHBhc3RlMCgiLi4vT3V0cHV0L1BpLyIscG9wc1tpXSwgIl9QaV9waXh5X3BlcjUwa1dpbmRvdy5jc3YiKSwgcm93Lm5hbWVzID0xICkKICAgIG1lYW5QaSRtZWFuW2ldPC1tZWFuKGRmJHBpLCBuYS5ybT1UKQogICAgbWVhblBpJHBvcFtpXTwtZ3N1YigiXFxkLisiLCIiLHBvcHNbaV0pCn0KCiNNZWFuIHBpIGNvbXBhcmlzb24KbWVhblBpJHBvcC55cjwtZmFjdG9yKG1lYW5QaSRwb3AueXIsIGxldmVscz1wb3BzKQptZWFuUGkkcG9wPC1mYWN0b3IobWVhblBpJHBvcCwgbGV2ZWxzPWMoIlRCIiwiUFdTIiwiU1MiLCJCQyIsIldBIiwiQ0EiKSkKCmdncGxvdChtZWFuUGksIGFlcyh4PXBvcC55ciwgeT1tZWFuLCBjb2xvcj1wb3ApKSsKICAgIGdlb21fcG9pbnQoc2l6ZT0zKSsKICAgIHhsYWIoIiIpK3lsYWIocGFzdGUwKCJNZWFuICIsZXhwcmVzc2lvbihwaSkpKSsKICAgIHRoZW1lX2xpbmVkcmF3KCkrCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWNvbHNbYyg1LDIsMSwgNCw2LDcpXSkrCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpCmdnc2F2ZSgiLi4vT3V0cHV0L1BpL21lYW5QaV9lc3RpbWF0ZWQuZnJvbS5QaXh5LnBuZyIsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNCwgZHBpPTMwMCkKCmBgYAohW10oLi4vT3V0cHV0L1BpL21lYW5QaV9lc3RpbWF0ZWQuZnJvbS5QaXh5LnBuZyl7d2lkdGg9NzAlfQoKYGBge3IgIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGV2YWw9RkFMU0V9Cgpwb3BzPC1jKCJUQjkxIiwiVEI5NiIsIlRCMDYiLCJUQjE3IiwiUFdTOTEiLCJQV1M5NiIsIlBXUzA3IiwiUFdTMTciLCJTUzk2IiwiU1MwNiIsIlNTMTciLCJCQzE3IiwiV0ExNyIsIkNBMTciKQojeWVhcjwtYygxOTkxLDE5OTYsMjAwNiwyMDE3LDE5OTEsMTk5NiwyMDA3LDIwMTcsMTk5NiwyMDA2LDIwMTcsMjAxNywyMDE3LDIwMTcpCgpQaTwtZGF0YS5mcmFtZSgpCmZvciAoaSBpbiAxOmxlbmd0aChwb3BzKSl7CiAgICBwaTwtcmVhZC5jc3YocGFzdGUwKCIuLi9PdXRwdXQvUGkvIixwb3BzW2ldLCAiX1BpX3BpeHlfcGVyNTBrV2luZG93LmNzdiIpLCByb3cubmFtZXMgPTEgKQogICAgcGkkcG9wLnlyPC1wb3BzW2ldCiAgICBwaSRwb3A8LWdzdWIoIlxcZC4rIiwiIixwb3BzW2ldKQogICAgUGk8LXJiaW5kKFBpLHBpKQp9CgpQaSRwb3AueXI8LWZhY3RvcihQaSRwb3AueXIsIGxldmVscz1wb3BzKQpQaSRwb3A8LWZhY3RvcihQaSRwb3AsIGxldmVscz1jKCJUQiIsIlBXUyIsIlNTIiwiQkMiLCJXQSIsIkNBIikpCiNtZWFucyA8LSBhZ2dyZWdhdGUocGkgfiBwb3AueXIsUGksIG1lYW4pCmdncGxvdChQaSwgYWVzKHg9cG9wLnlyLCB5PXBpLCBjb2xvcj1wb3ApKSsKICAgIGdlb21fYm94cGxvdChhZXMoY29sb3I9cG9wKSwgb3V0bGllci5hbHBoYSA9IDAuMiwgb3V0bGllci5zaXplID0gMC42KSsKICAgIHRoZW1lX2NsYXNzaWMoKSsgCiAgICBnZW9tX3BvaW50KHN0YXQgPSAic3VtbWFyeSIsIGZ1biA9ICJtZWFuIiwgY29sb3I9ImdyYXk0MCIpKwogICAgeGxhYigiIikreWxhYihleHByZXNzaW9uKHBpKSkrCiAgICBnZW9tX3BvaW50KHN0YXQ9InN1bW1hcnkiLCBmdW49bWVhbikrCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWNvbHNbYyg1LDIsMSwgNCw2LDcpXSkKICAgICNnZW9tX3RleHQoZGF0YSA9IG1lYW5zLCBhZXMobGFiZWwgPSByb3VuZChwaSwgZGlnaXRzPTUpLCB5ID0gcGkgKyAwLjAyKSwgY29sb3I9ImdyYXk0MCIpCmdnc2F2ZShwYXN0ZTAoIi4uL091dHB1dC9QaS9QaV9waXh5X2FsbF9ib3hwbG90LnBuZyIpLCB3aWR0aCA9IDQuNSwgaGVpZ2h0ID0gMywgZHBpPTIwMCkKCmdncGxvdChQaSwgYWVzKHg9cG9wLnlyLCB5PXBpLCBjb2xvcj1wb3AsIGZpbGw9cG9wKSkrCiAgICBnZW9tX2JveHBsb3QoYWVzKGNvbG9yPXBvcCksIG91dGxpZXIuYWxwaGEgPSAwLjEsIG91dGxpZXIuc2l6ZSA9IDAuMykrCiAgICB0aGVtZV9jbGFzc2ljKCkrCiAgICBnZW9tX3BvaW50KHN0YXQgPSAic3VtbWFyeSIsIGZ1biA9ICJtZWFuIiwgY29sb3I9ImdyYXk0MCIpKwogICAgeGxhYigiIikreWxhYihleHByZXNzaW9uKHBpKSkreWxpbSgwLDAuMDA0NykrCiAgICBnZW9tX3BvaW50KHN0YXQ9InN1bW1hcnkiLCBmdW49bWVhbiwgc2l6ZT0yLjUpKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jb2xzKSsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1wYXN0ZTAoY29scywgIjk5IikpKwogICAgdGhlbWUoYXhpcy50aXRsZS55ID0gIGVsZW1lbnRfdGV4dChzaXplPTE1KSwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQogICAgCmdnc2F2ZShwYXN0ZTAoIi4uL091dHB1dC9QaS9QaV9waXh5X2FsbF9ib3hwbG90X3pvb21lZDIucG5nIiksIHdpZHRoID0gOCwgaGVpZ2h0ID0gMy40LCBkcGk9MzAwKQpgYGAKIVtdKC4uL091dHB1dC9QaS9QaV9waXh5X2FsbF9ib3hwbG90X3pvb21lZC5wbmcpe3dpZHRoPTc1JX0KCgoKIyMjIEJvb3RzdHJhcCBwaSB2YWx1ZXMgdG8gZ2V0IDk1JSBDSQoKYGBge3IgZXZhbD1GQUxTRSx3YXJuaW5nPUZBTFNFLG1lc3NhZ2U9RkFMU0V9CgojIGF2ZXJhZ2UgdGhldGEgdmFsdWVzIGFjcm9zcyBzaXRlcwoKIyMjIyMjIyMjIyMjIwojIFBhcmFtZXRlcnMKIyMjIyMjIyMjIyMjIwojIG51bWJlciBvZiBjaHJvbW9zb21lcyBpbiBlYWNoIHNhbXBsZQpuY2hyPTI2Cm5ib290IDwtIDEwMDAKCiMjIyMjIyMjIyMjIyMjIyMjIyMjCiMgbG9hZCBmdW5jdGlvbnMKcmVxdWlyZShkYXRhLnRhYmxlKQpyZXF1aXJlKGJvb3QpICMgZm9yIGJvb3RzdHJhcCBDSXMKCgojIEZvciBUYWppbWEncyBEIGNhbGNzLiBBZnRlciBodHRwczovL2dpdGh1Yi5jb20vQU5HU0QvYW5nc2QvYmxvYi9tYXN0ZXIvbWlzYy9zdGF0cy5jcHAKYTFmIDwtIGZ1bmN0aW9uKG5zYW0pIHJldHVybihzdW0oMS9zZXEoMSwgbnNhbS0xKSkpCmEyZiA8LSBmdW5jdGlvbihuc2FtKSByZXR1cm4oc3VtKDEvKHNlcSgxLCBuc2FtLTEpKnNlcSgxLCBuc2FtLTEpKSkpCmIxZiA8LSBmdW5jdGlvbihuc2FtKSByZXR1cm4oKG5zYW0gKyAxKS8oMyoobnNhbS0xKSkpCmIyZiA8LSBmdW5jdGlvbihuc2FtKSByZXR1cm4oKDIqKG5zYW0qbnNhbSArIG5zYW0gKyAzKSkvKDkqbnNhbSoobnNhbSAtIDEpKSkKYzFmIDwtIGZ1bmN0aW9uKGExLCBiMSkgcmV0dXJuKGIxIC0gKDEvYTEpKQpjMmYgPC0gZnVuY3Rpb24obnNhbSwgYTEsIGEyLCBiMikgcmV0dXJuKGIyIC0gKChuc2FtICsgMikvKGExKm5zYW0pKSArIChhMi8oYTEgKiBhMSkpKQplMWYgPC0gZnVuY3Rpb24oYTEsIGMxKSByZXR1cm4oYzEvYTEpCmUyZiA8LSBmdW5jdGlvbihhMSwgYTIsIGMyKSByZXR1cm4oYzIvKChhMSphMSkgKyBhMikpCgojIFRhamltYSdzIEQgY2FsY3VsYXRpb24KIyBuc2FtOiBzYW1wbGUgc2l6ZQojIHRoZXRhVzogV2F0dGVyc29uJ3MgdGhldGEgKCMgc2VncmVnYXRpbmcgc2l0ZXMgLyBhMSkKIyBzdW1rOiB0aGV0YSBwaSAoYXZlcmFnZSBudW1iZXIgb2YgU05QcyBpbiBwYWlyd2lzZSBjb21wYXJpc29ucykKIyBhZnRlciBodHRwczovL2dpdGh1Yi5jb20vQU5HU0QvYW5nc2QvYmxvYi9tYXN0ZXIvbWlzYy9zdGF0cy5jcHAKdGFqZCA8LSBmdW5jdGlvbihuc2FtLCB0aGV0YVcsIHN1bWspewoJYTEgPC0gYTFmKG5zYW0pCglzZWdzaXRlcyA8LSB0aGV0YVcgKiBhMQoJaWYoc2Vnc2l0ZXMgPT0gMCkgcmV0dXJuKDApCglhMiA8LSBhMmYobnNhbSkKCWIxIDwtIGIxZihuc2FtKQogIAliMiA8LSBiMmYobnNhbSkKCWMxIDwtIGMxZihhMSwgYjEpCgljMiA8LSBjMmYobnNhbSwgYTEsIGEyLCBiMikKCWUxIDwtIGUxZihhMSwgYzEpCgllMiA8LSBlMmYoYTEsIGEyLCBjMikKCXJlcyA8LSAoc3VtayAtICh0aGV0YVcpKS9zcXJ0KChlMSpzZWdzaXRlcykgKyAoKGUyKnNlZ3NpdGVzKSooc2Vnc2l0ZXMtMSkpKQoJcmV0dXJuKHJlcykKfQoKIyBjYWxjIHRoZXRhcwpjYWxjdGhldGFzIDwtIGZ1bmN0aW9uKGRhdCwgbmNociwgbmxvY2kpewoJIyBjYWxjIGF2ZSB0aGV0YQoJdGhldGFzIDwtIGFzLm51bWVyaWMoZGF0WywgLih0VyA9IHN1bShleHAoV2F0dGVyc29uKS9ubG9jaSwgbmEucm0gPSBUUlVFKSwgdFAgPSBzdW0oZXhwKFBhaXJ3aXNlKS9ubG9jaSwgbmEucm0gPSBUUlVFKSldKQoKCSMgY2FsY3VsYXRlIFRhamltYSdzIEQKCXRoZXRhc1szXSA8LSB0YWpkKG5jaHIsIHRoZXRhc1sxXSwgdGhldGFzWzJdKQoJCgkjcmV0dXJuCgluYW1lcyh0aGV0YXMpIDwtIGMoJ3RXJywgJ3RQJywgJ3REJykKCXJldHVybih0aGV0YXMpCn0KCiMgY2FsY3VsYXRlIHN0YXRzIGZyb20gc3BlY2lmaWVkIExHcyBmb3IgYmxvY2sgYm9vdHN0cmFwcGluZyBhY3Jvc3MgTEdzCnRoZXRhYmxvY2sgPC0gZnVuY3Rpb24obGdzLCBpbmRpY2VzLCBhbGxkYXRhLCBuY2hyLCByZWdzKXsKCSMgbWFrZSBib290c3RyYXBwZWQgZGF0YXNldAoJbXlkYXRhIDwtIGRvLmNhbGwoInJiaW5kIiwgbGFwcGx5KGluZGljZXMsIGZ1bmN0aW9uKG4pIHN1YnNldChhbGxkYXRhLCBDaHJvbW89PWxnc1tuXSkpKQoJCgkjIGNhbGN1bGF0ZSBudW1iZXIgb2YgY2FsbGFibGUgbG9jaSwgZ2l2ZW4gdGhlIExHcyBpbiB0aGlzIGJvb3RzdHJhcHBlZCBzYW1wbGUKCW5sb2NpIDwtIHJlZ3NbQ2hyb21vICVpbiUgbGdzLCAuKGxlbiA9IFBvczIgLSBQb3MxICsgMSksIGJ5ID0gLihDaHJvbW8sIFBvczEpXVssIHN1bShsZW4pXSAjIHN1bSBvZiBicCBpbiB0aGUgY2FsbGFibGUgcmVnaW9uCgkKCSMgY2FsYyB0aGV0YXMKCXRoZXRhcyA8LSBjYWxjdGhldGFzKG15ZGF0YSwgbmNociwgbmxvY2kpCgkKCSMgcmV0dXJuCglyZXR1cm4odGhldGFzKQp9CgojdXNpbmcgd2luZG93IGJhc2VkIGFuZ3NkIGZpbGUgKHVzZSBwcmVrbm93biBsb2NpIGluIDUwMDAwIHdpbmRvd3MpCnRoZXRhYmxvY2syIDwtIGZ1bmN0aW9uKGxncywgaW5kaWNlcywgYWxsZGF0YSwgbmNociwgcmVncyl7CgkjIG1ha2UgYm9vdHN0cmFwcGVkIGRhdGFzZXQKCW15ZGF0YSA8LSBkby5jYWxsKCJyYmluZCIsIGxhcHBseShpbmRpY2VzLCBmdW5jdGlvbihuKSBzdWJzZXQoYWxsZGF0YSwgQ2hyb21vPT1sZ3Nbbl0pKSkKCQoJIyBjYWxjdWxhdGUgbnVtYmVyIG9mIGNhbGxhYmxlIGxvY2ksIGdpdmVuIHRoZSBMR3MgaW4gdGhpcyBib290c3RyYXBwZWQgc2FtcGxlCgkjbmxvY2kgPC0gcmVnc1tDaHJvbW8gJWluJSBsZ3MsIC4obGVuID0gUG9zMiAtIFBvczEgKyAxKSwgYnkgPSAuKENocm9tbywgUG9zMSldWywgc3VtKGxlbildICMgc3VtIG9mIGJwIGluIHRoZSBjYWxsYWJsZSByZWdpb24KCglubG9jaSA8LSBhbGxkYXRhW0Nocm9tbyAlaW4lIGxncyxzdW0oblNpdGVzKV0gIyBzdW0gb2YgYnAgaW4gdGhlIGNhbGxhYmxlIHJlZ2lvbgoJCgkjIGNhbGMgdGhldGFzCgl0aGV0YXMgPC0gY2FsY3RoZXRhcyhteWRhdGEsIG5jaHIsIG5sb2NpKQoJCgkjIHJldHVybgoJcmV0dXJuKHRoZXRhcykKfQoKCiMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBMb2FkIGRhdGEKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwphbGxkYXRhPC1kYXQKIyBsb2FkIGFsbCBsb2NpIHRoZXRhIGNhbGNzCmRhdDwtZnJlYWQoJy4uL0RhdGEvbmV3X3ZjZi9hbmdzZC9mcm9tVkNGL0JDMTdfbWFmMDAudGhldGFzNTBrV2luZG93Lmd6LnBlc3RQRycpCnNldG5hbWVzKGRhdCwgJ0NocicsICdDaHJvbW8nKQoKZGF0Q2FuNDAgPC0gZnJlYWQoJ2FuYWx5c2lzL3RoZXRhcy5DYW5fNDAucGVzdFBHLmd6JykKZGF0Q2FuMTQgPC0gZnJlYWQoJ2FuYWx5c2lzL3RoZXRhcy5DYW5fMTQucGVzdFBHLmd6JykKZGF0TG9mMDcgPC0gZnJlYWQoJ2FuYWx5c2lzL3RoZXRhcy5Mb2ZfMDcucGVzdFBHLmd6JykKZGF0TG9mMTEgPC0gZnJlYWQoJ2FuYWx5c2lzL3RoZXRhcy5Mb2ZfMTEucGVzdFBHLmd6JykKZGF0TG9mMTQgPC0gZnJlYWQoJ2FuYWx5c2lzL3RoZXRhcy5Mb2ZfMTQucGVzdFBHLmd6JykKCiMgZ2F0ayBsb2NpCmRhdENhbjQwZ2F0ayA8LSBmcmVhZCgnYW5hbHlzaXMvdGhldGFzLkNhbl80MC5nYXRrLnBlc3RQRy5neicpCmRhdENhbjE0Z2F0ayA8LSBmcmVhZCgnYW5hbHlzaXMvdGhldGFzLkNhbl8xNC5nYXRrLnBlc3RQRy5neicpCmRhdExvZjA3Z2F0ayA8LSBmcmVhZCgnYW5hbHlzaXMvdGhldGFzLkxvZl8wNy5nYXRrLnBlc3RQRy5neicpCmRhdExvZjExZ2F0ayA8LSBmcmVhZCgnYW5hbHlzaXMvdGhldGFzLkxvZl8xMS5nYXRrLnBlc3RQRy5neicpCmRhdExvZjE0Z2F0ayA8LSBmcmVhZCgnYW5hbHlzaXMvdGhldGFzLkxvZl8xNC5nYXRrLnBlc3RQRy5neicpCgojIGZpeCBuYW1lCnNldG5hbWVzKGRhdENhbjQwLCAnI0Nocm9tbycsICdDaHJvbW8nKQpzZXRuYW1lcyhkYXRDYW4xNCwgJyNDaHJvbW8nLCAnQ2hyb21vJykKc2V0bmFtZXMoZGF0TG9mMDcsICcjQ2hyb21vJywgJ0Nocm9tbycpCnNldG5hbWVzKGRhdExvZjExLCAnI0Nocm9tbycsICdDaHJvbW8nKQpzZXRuYW1lcyhkYXRMb2YxNCwgJyNDaHJvbW8nLCAnQ2hyb21vJykKCnNldG5hbWVzKGRhdENhbjQwZ2F0aywgJyNDaHJvbW8nLCAnQ2hyb21vJykKc2V0bmFtZXMoZGF0Q2FuMTRnYXRrLCAnI0Nocm9tbycsICdDaHJvbW8nKQpzZXRuYW1lcyhkYXRMb2YwN2dhdGssICcjQ2hyb21vJywgJ0Nocm9tbycpCnNldG5hbWVzKGRhdExvZjExZ2F0aywgJyNDaHJvbW8nLCAnQ2hyb21vJykKc2V0bmFtZXMoZGF0TG9mMTRnYXRrLCAnI0Nocm9tbycsICdDaHJvbW8nKQoKd2luZG93bmFtZXM8LWNvbG5hbWVzKGRhdClbMV0KY29sbmFtZXMoZGF0KVsxXTwtIndpbmRvdyIKIyMgbGlzdCBvZiBjYWxsYWJsZSByZWdpb25zCgpkYXQkd2luZG93PC1nc3ViKCJcXCgiLCcnLCBkYXQkd2luZG93KQpkYXQkd2luZG93PC1nc3ViKCJcXCkkIiwnJywgZGF0JHdpbmRvdykKZGF0JHdpbmRvdzwtZ3N1YigiXFwpIiwnLCcsIGRhdCR3aW5kb3cpCndpbmRvd3MxPC1zdHJfc3BsaXRfZml4ZWQoZGF0JHdpbmRvdywiLCIsNikgCmNvbG5hbWVzKHdpbmRvd3MxKTwtYygnSW5kZXhTdGFydCcsICdJbmRleFN0b3AnLCdmaXJzdFBvc193aXRoRGF0YScsJ2xhc3RQb3Nfd2l0aERhdGEnLCdXaW5TdGFydCcsJ1dpblN0b3AnKQoKZGF0PC1jYmluZCh3aW5kb3dzMSwgZGF0KQoKcmVnczwtZGF0WyxjKCJDaHJvbW8iLCJXaW5TdGFydCIsIldpblN0b3AiKV0KbmFtZXMocmVncyk8LWMoJ0Nocm9tbycsICdQb3MxJywgJ1BvczInKQojcmVncyA8LSBmcmVhZCgnZGF0YV8yMDIwLjA1LjA3L0NhbGxhYmxlX2Jhc2VzX2dhZG1vcjIuYmVkJykKI3NldG5hbWVzKHJlZ3MsIGMoJ0Nocm9tbycsICdQb3MxJywgJ1BvczInKSkKIwojIyBsaXN0IG9mIG5vIGRhbWFnZSBzaXRlcwojbm9kYW0gPC0gZnJlYWQoJ2RhdGFfMjAyMC4wNS4wNy9HQVRLX2ZpbHRlcmVkX1NOUF9ub19kYW0yLnRhYicpCiNzZXRuYW1lcyhub2RhbSwgYygnQ2hyb21vJywgJ1BvcycsICdSRUYnLCAnQUxUJykpCiMKIwojIyByZW1vdmUgdW5wbGFjZWQKI2RhdENhbjQwIDwtIGRhdENhbjQwW2dyZXAoJ1VucGxhY2VkJywgQ2hyb21vLCBpbnZlcnQgPSBUUlVFKSwgXQojZGF0Q2FuMTQgPC0gZGF0Q2FuMTRbZ3JlcCgnVW5wbGFjZWQnLCBDaHJvbW8sIGludmVydCA9IFRSVUUpLCBdCiNkYXRMb2YwNyA8LSBkYXRMb2YwN1tncmVwKCdVbnBsYWNlZCcsIENocm9tbywgaW52ZXJ0ID0gVFJVRSksIF0KI2RhdExvZjExIDwtIGRhdExvZjExW2dyZXAoJ1VucGxhY2VkJywgQ2hyb21vLCBpbnZlcnQgPSBUUlVFKSwgXQojZGF0TG9mMTQgPC0gZGF0TG9mMTRbZ3JlcCgnVW5wbGFjZWQnLCBDaHJvbW8sIGludmVydCA9IFRSVUUpLCBdCiMKI2RhdENhbjQwZ2F0ayA8LSBkYXRDYW40MGdhdGtbZ3JlcCgnVW5wbGFjZWQnLCBDaHJvbW8sIGludmVydCA9IFRSVUUpLCBdCiNkYXRDYW4xNGdhdGsgPC0gZGF0Q2FuMTRnYXRrW2dyZXAoJ1VucGxhY2VkJywgQ2hyb21vLCBpbnZlcnQgPSBUUlVFKSwgXQojZGF0TG9mMDdnYXRrIDwtIGRhdExvZjA3Z2F0a1tncmVwKCdVbnBsYWNlZCcsIENocm9tbywgaW52ZXJ0ID0gVFJVRSksIF0KI2RhdExvZjExZ2F0ayA8LSBkYXRMb2YxMWdhdGtbZ3JlcCgnVW5wbGFjZWQnLCBDaHJvbW8sIGludmVydCA9IFRSVUUpLCBdCiNkYXRMb2YxNGdhdGsgPC0gZGF0TG9mMTRnYXRrW2dyZXAoJ1VucGxhY2VkJywgQ2hyb21vLCBpbnZlcnQgPSBUUlVFKSwgXQoKcmVncyA8LSByZWdzW0Nocm9tbyAhPSAnVW5wbGFjZWQnLCBdCm5vZGFtIDwtIG5vZGFtW0Nocm9tbyAhPSAnVW5wbGFjZWQnLCBdCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKIyBjcmVhdGUgdGFibGUgb2YgbG9jaSB0cmltbWVkIHRvIG5vIGRhbWFnZSBzaXRlcwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKCmRhdENhbjQwZ2F0a25kIDwtIG1lcmdlKGRhdENhbjQwLCBub2RhbVssIC4oQ2hyb21vLCBQb3MpXSwgYnkgPSBjKCdDaHJvbW8nLCAnUG9zJykpICMgdHJpbQpkYXRDYW4xNGdhdGtuZCA8LSBtZXJnZShkYXRDYW4xNCwgbm9kYW1bLCAuKENocm9tbywgUG9zKV0sIGJ5ID0gYygnQ2hyb21vJywgJ1BvcycpKSAjIHRyaW0KZGF0TG9mMDdnYXRrbmQgPC0gbWVyZ2UoZGF0TG9mMDcsIG5vZGFtWywgLihDaHJvbW8sIFBvcyldLCBieSA9IGMoJ0Nocm9tbycsICdQb3MnKSkgIyB0cmltCmRhdExvZjExZ2F0a25kIDwtIG1lcmdlKGRhdExvZjExLCBub2RhbVssIC4oQ2hyb21vLCBQb3MpXSwgYnkgPSBjKCdDaHJvbW8nLCAnUG9zJykpICMgdHJpbQpkYXRMb2YxNGdhdGtuZCA8LSBtZXJnZShkYXRMb2YxNCwgbm9kYW1bLCAuKENocm9tbywgUG9zKV0sIGJ5ID0gYygnQ2hyb21vJywgJ1BvcycpKSAjIHRyaW0KCgojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIFJ1biB0aGV0YSBjYWxjdWxhdGlvbnMKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMKI25sb2NpIDwtIHJlZ3NbLCAuKGxlbiA9IFBvczIgLSBQb3MxICsgMSksIGJ5ID0gLihDaHJvbW8sIFBvczEpXVssIHN1bShsZW4pXSAjIHN1bSBvZiBicCBpbiB0aGUgY2FsbGFibGUgcmVnaW9uCgpubG9jaTwtZGF0JG5TaXRlcwoKIyBhbGwgbG9jaQpjYWxjdGhldGFzKGRhdCwgbmNociwgbmxvY2kpCmNhbGN0aGV0YXMoZGF0Q2FuMTQsIG5jaHJDYW4xNCwgbmxvY2kpCmNhbGN0aGV0YXMoZGF0TG9mMDcsIG5jaHJMb2YwNywgbmxvY2kpCmNhbGN0aGV0YXMoZGF0TG9mMTEsIG5jaHJMb2YxMSwgbmxvY2kpCmNhbGN0aGV0YXMoZGF0TG9mMTQsIG5jaHJMb2YxNCwgbmxvY2kpCgojIGdhdGsgbG9jaQpjYWxjdGhldGFzKGRhdENhbjQwZ2F0aywgbmNockNhbjQwLCBubG9jaSkKY2FsY3RoZXRhcyhkYXRDYW4xNGdhdGssIG5jaHJDYW4xNCwgbmxvY2kpCmNhbGN0aGV0YXMoZGF0TG9mMDdnYXRrLCBuY2hyTG9mMDcsIG5sb2NpKQpjYWxjdGhldGFzKGRhdExvZjExZ2F0aywgbmNockxvZjExLCBubG9jaSkKY2FsY3RoZXRhcyhkYXRMb2YxNGdhdGssIG5jaHJMb2YxNCwgbmxvY2kpCgojIGdhdGsgbm8gZGFtYWdlIGxvY2kKY2FsY3RoZXRhcyhkYXRDYW40MGdhdGtuZCwgbmNockNhbjQwLCBubG9jaSkKY2FsY3RoZXRhcyhkYXRDYW4xNGdhdGtuZCwgbmNockNhbjE0LCBubG9jaSkKY2FsY3RoZXRhcyhkYXRMb2YwN2dhdGtuZCwgbmNockxvZjA3LCBubG9jaSkKY2FsY3RoZXRhcyhkYXRMb2YxMWdhdGtuZCwgbmNockxvZjExLCBubG9jaSkKY2FsY3RoZXRhcyhkYXRMb2YxNGdhdGtuZCwgbmNockxvZjE0LCBubG9jaSkKCgoKCiMgYmxvY2sgYm9vdHN0cmFwcGluZyBhY3Jvc3MgTEdzCgojbGdzIDwtIGRhdENhbjQwWywgc29ydCh1bmlxdWUoQ2hyb21vKSldCmRhdGxpc3QgPC0gbGlzdChkYXRDYW40MCwgZGF0Q2FuMTQsIGRhdExvZjA3LCBkYXRMb2YxMSwgZGF0TG9mMTQsIAoJCQkJZGF0Q2FuNDBnYXRrLCBkYXRDYW4xNGdhdGssIGRhdExvZjA3Z2F0aywgZGF0TG9mMTFnYXRrLCBkYXRMb2YxNGdhdGssCgkJCQlkYXRDYW40MGdhdGtuZCwgZGF0Q2FuMTRnYXRrbmQsIGRhdExvZjA3Z2F0a25kLCBkYXRMb2YxMWdhdGtuZCwgZGF0TG9mMTRnYXRrbmQpCm5hbWVzKGRhdGxpc3QpIDwtIGMoJ0NhbjQwIGFsbCBsb2NpJywgJ0NhbjE0IGFsbCBsb2NpJywgJ0xvZjA3IGFsbCBsb2NpJywgJ0xvZjExIGFsbCBsb2NpJywgJ0xvZjE0IGFsbCBsb2NpJywgCgkJCQkJJ0NhbjQwIGdhdGsgbG9jaScsICdDYW4xNCBnYXRrIGxvY2knLCAnTG9mMDcgZ2F0ayBsb2NpJywgJ0xvZjExIGdhdGsgbG9jaScsICdMb2YxNCBnYXRrIGxvY2knLAoJCQkJCSdDYW40MCBnYXRrIG5vIGRhbSBsb2NpJywgJ0NhbjE0IGdhdGsgbm8gZGFtIGxvY2knLCAnTG9mMDcgZ2F0ayBubyBkYW0gbG9jaScsICdMb2YxMSBnYXRrIG5vIGRhbSBsb2NpJywgCgkJCQkJJ0xvZjE0IGdhdGsgbm8gZGFtIGxvY2knKQpuY2hybGlzdCA8LSBsaXN0KG5jaHJDYW40MCwgbmNockNhbjE0LCBuY2hyTG9mMDcsIG5jaHJMb2YxMSwgbmNockxvZjE0LCBuY2hyQ2FuNDAsIG5jaHJDYW4xNCwgbmNockxvZjA3LCBuY2hyTG9mMTEsIG5jaHJMb2YxNCwgbmNockNhbjQwLCBuY2hyQ2FuMTQsIG5jaHJMb2YwNywgbmNockxvZjExLCBuY2hyTG9mMTQpCgp0aGV0YWJvb3RvdXQgPC0gZGF0YS5mcmFtZSh0eXBlID0gbmFtZXMoZGF0bGlzdCksIHRXID0gTkEsIHRXbDk1ID0gTkEsIHRXdTk1ID0gTkEsIHRQID0gTkEsIHRQbDk1ID0gTkEsIHRQdTk1ID0gTkEsIHREID0gTkEsIHREbDk1ID0gTkEsIHREdTk1ID0gTkEpCgoKIyMjIyMKCmxncyA8LSBkYXRbLCBzb3J0KHVuaXF1ZShDaHJvbW8pKV0KCmJvb3RsZyA8LSBib290KGxncywgdGhldGFibG9jazIsIG5ib290LCAgYWxsZGF0YSA9IGRhdCwgbmNociA9IG5jaHIsIHJlZ3MgPSByZWdzKQoKCmZvcihpIGluIDE6bGVuZ3RoKGRhdGxpc3QpKXsKCXByaW50KG5hbWVzKGRhdGxpc3QpW2ldKQogICAgCiAgICAKCWJvb3RsZyA8LSBib290KGxncywgdGhldGFibG9jaywgbmJvb3QsICBhbGxkYXRhID0gZGF0bGlzdFtbaV1dLCBuY2hyID0gbmNocmxpc3RbW2ldXSwgcmVncyA9IHJlZ3MpCgkKCXByaW50KGJvb3RsZykKCWNpVyA8LSBib290LmNpKGJvb3RsZywgdHlwZSA9IGMoJ3BlcmMnKSwgaW5kZXggPSAxKQoJY2lQIDwtIGJvb3QuY2koYm9vdGxnLCB0eXBlID0gYygncGVyYycpLCBpbmRleCA9IDIpCgljaUQgPC0gYm9vdC5jaShib290bGcsIHR5cGUgPSBjKCdwZXJjJyksIGluZGV4ID0gMykKCQoJdGhldGFib290b3V0JHRXW2ldIDwtIGJvb3RsZyR0MFsxXSAjIHRoZSBwb2ludCBlc3RpbWF0ZXMKCXRoZXRhYm9vdG91dCR0UFtpXSA8LSBib290bGckdDBbMl0JCgl0aGV0YWJvb3RvdXQkdERbaV0gPC0gYm9vdGxnJHQwWzNdCgoJdGhldGFib290b3V0JHRXbDk1W2ldIDwtIGNpVyRwZXJjZW50WzRdICMgdGhlIGNvbmZpZGVuY2UgaW50ZXJ2YWxzCgl0aGV0YWJvb3RvdXQkdFd1OTVbaV0gPC0gY2lXJHBlcmNlbnRbNV0KCgl0aGV0YWJvb3RvdXQkdFBsOTVbaV0gPC0gY2lQJHBlcmNlbnRbNF0KCXRoZXRhYm9vdG91dCR0UHU5NVtpXSA8LSBjaVAkcGVyY2VudFs1XQoKCXRoZXRhYm9vdG91dCR0RGw5NVtpXSA8LSBjaUQkcGVyY2VudFs0XQoJdGhldGFib290b3V0JHREdTk1W2ldIDwtIGNpRCRwZXJjZW50WzVdCn0KCiMgc2F2ZQp3cml0ZS5jc3YodGhldGFib290b3V0LCBmaWxlID0gJ2FuYWx5c2lzL3RoZXRhcy5ib290LmNpcy5jc3YnKQoKYGBgCgoKIyBGc3QgYmV0d2VlbiBwb3B1bGF0aW9ucyBpbiAxOTkxLCAxOTk2IGFuZCAyMDA2LzcKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGV2YWw9RkFMU0V9CgojIDEuIFkxOTk2CnBvcHM8LWMoIlBXUzk2IiwiU1M5NiIsIlRCOTYiKQpjb21iPC10KGNvbWJuKHBvcHMsMikpCgpmc3Q8LWRhdGEuZnJhbWUoKQpmb3IgKGkgaW4gMTogbnJvdyhjb21iKSl7CiAgICBwb3AxPC1jb21iW2ksMV0KICAgIHBvcDI8LWNvbWJbaSwyXQogICAgZGY8LXJlYWQuZGVsaW0ocGFzdGUwKCIuLi9EYXRhL25ld192Y2YvYW5nc2QvZnJvbVZDRi8yRC9mc3RfZm9sZGVkXyIscG9wMSwiXyIscG9wMiwiXzUwa1dpbmRvd19tYWYwMCIpKQogICAgY29uYW1lczwtY29sbmFtZXMoZGYpWzI6NF0KICAgIGNvbG5hbWVzKGRmKVs0XTwtIkZzdCIKICAgIGNvbG5hbWVzKGRmKVsxOjNdPC1jb25hbWVzCiAgICBkZiRwb3A8LXBhc3RlMChwb3AxLCIudnMuIixwb3AyKQogICAgZGYkY2g9YXMuaW50ZWdlcihnc3ViKCJjaHIiLCIiLCBkZiRjaHIpKQogICAgZGY8LWRmW29yZGVyKGRmJGNoKSxdCiAgICBkZiRsb2M8LTE6bnJvdyhkZikKICAgIGZzdDwtcmJpbmQoZnN0LCBkZikKfQoKZXZlbnM8LXBhc3RlMCgiY2hyIixzZXEoMiwyNiwgYnk9MikpCiNQbG90IEZzdCB2YWx1ZXMgYWNyb3NzIEdlbm9tZQpmc3QkY29sb3I8LSJjb2wxIgpmc3QkY29sb3JbZnN0JGNociAlaW4lIGV2ZW5zXTwtImNvbDIiCmZzdCRwb3A8LWZhY3Rvcihmc3QkcG9wLCBsZXZlbHM9dW5pcXVlKGZzdCRwb3ApKQoKI2FkZCBjaHJvbW9zb21lIG51bWJlcgpkZjwtZnN0W2ZzdCRwb3A9PSJQV1M5Ni52cy5TUzk2IixdCnJvd3M8LWRhdGEuZnJhbWUoY2hyPTE6MjYpCmZvciAoaSBpbiAxOjI2KXsKICAgIGlmIChpID09MSl7CiAgICAgICAgcm93cyRuW2ldPC1ucm93KGRmW2RmJGNoPT1pLF0pCiAgICAgICAgcm93cyRtaWRkbGVbaV08LW5yb3coZGZbZGYkY2g9PWksXSkvMgogICAgfQogICAgaWYgKGkgPjEpewogICAgICAgIHJvd3MkbltpXTwtbnJvdyhkZltkZiRjaD09aSxdKQogICAgICAgIHJvd3MkbWlkZGxlW2ldPC1zdW0ocm93cyRuWzE6KGktMSldKStyb3dzJG5baV0vMgogICAgfQp9CgpnZ3Bsb3QoZnN0LCBhZXMoeD1sb2MsIHk9RnN0LCBjb2xvcj1jb2xvcikpKwogICAgZmFjZXRfd3JhcCh+cG9wLCBuY29sID0gMSwgc3RyaXAucG9zaXRpb249InJpZ2h0IikrCiAgICBnZW9tX3BvaW50KHNpemU9MC4yLCBhbHBoYT0wLjYpKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJncmF5NjAiLCJzdGVlbGJsdWUiKSkrCiAgICB0aGVtZV9idygpK2dndGl0bGUoIjE5OTYiKSsKICAgIHlsYWIoIkZzdCIpK3hsYWIoJ0dlbm9tZSBwb3NpdGlvbicpKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCksIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSkrCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPXJvd3MkbWlkZGxlLCBsYWJlbHM9MToyNikKZ2dzYXZlKCIuLi9PdXRwdXQvU0ZTL1kxOTk2X0ZzdF9wYWlyd2lzZV9jb21wYXJpc29uLnBuZyIsIHdpZHRoID0gMTYsIGhlaWdodCA9IDcsIGRwaT0zMDApCgoKY29tcGFyZTwtdW5pcXVlKGZzdCRwb3ApCnBhaXJmc3Q8LWRhdGEuZnJhbWUobWF0cml4KG5jb2w9MywgbnJvdz0zKSwgcm93Lm5hbWVzPWMoIlRCOTYiLCJQV1M5NiIsIlNTOTYiKSkKY29sbmFtZXMocGFpcmZzdCk8LWMoIlRCOTYiLCJQV1M5NiIsIlNTOTYiKQpmb3IgKGkgaW4gMTozKXsKICAgIHBvcDE8LWNvbWJbaSwxXQogICAgcG9wMjwtY29tYltpLDJdCiAgICBkZjwtZnN0W2ZzdCRwb3A9PWNvbXBhcmVbaV0sXQogICAgcGFpcmZzdFtwb3AxLHBvcDJdPC1tZWFuKGRmJEZzdCwgbmEucm09VCkKICAgIHBhaXJmc3RbcG9wMixwb3AxXTwtbWVhbihkZiRGc3QsIG5hLnJtPVQpCn0Kd3JpdGUuY3N2KHBhaXJmc3QsIi4uL091dHB1dC9TRlMvWTE5OTZfcGFpcndpc2VGc3RfbWF0cml4LmNzdiIpCgojZGY8LXJlYWQuY3N2KCIuLi9PdXRwdXQvU0ZTL1kxOTk2X3BhaXJ3aXNlRnN0X21hdHJpeC5jc3YiLCByb3cubmFtZXMgPSAxKQpkZjwtcGFpcmZzdApkaWFnKGRmKTwtMApkZltsb3dlci50cmkoZGYpXTwtTkEKZGYkcG9wPC1yb3duYW1lcyhkZikKZGZtPC1tZWx0KGRmLG5hLnJtPVQsIGlkLnZhcnM9J3BvcCcpCiNOQSB0byBkaWFnb25hbApkZm0kdmFsdWVbZGZtJHZhbHVlPT0wXTwtTkEKZGZtJHBvcDwtZmFjdG9yKGRmbSRwb3AsIGxldmVscz1jKCJUQjk2IiwiUFdTOTYiLCJTUzk2IikpCmRmbSR2YWx1ZTwtcm91bmQoZGZtJHZhbHVlLCA0KQpnZ3Bsb3QoZGF0YSA9IGRmbSwgYWVzKHBvcCwgdmFyaWFibGUsIGZpbGwgPSB2YWx1ZSkpKwogICAgZ2VvbV90aWxlKGNvbG9yID0gIndoaXRlIikrCiAgICBzY2FsZV9maWxsX2dyYWRpZW50bihjb2xvcnM9Yygid2hpdGUiLCAiIzBDNTRGRkNDIiksIGxpbWl0cz1jKDAsIChtYXgoZGZtJHZhbHVlLCBuYS5ybT1UKSswLjA1KSksbmEudmFsdWU9ImdyYXk4MCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgbmFtZT0iRnN0IikrCiAgICB0aGVtZV9taW5pbWFsKCkrIHhsYWIoIiIpK3lsYWIoIiIpKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwLCB2anVzdCA9IDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEyLCBoanVzdCA9IDAuNSkpKwogICAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkrCiAgICBjb29yZF9maXhlZCgpKwogICAgZ2VvbV90ZXh0KGFlcyhwb3AsIHZhcmlhYmxlLCBsYWJlbCA9IHZhbHVlKSwgY29sb3IgPSAiYmxhY2siLCBzaXplID0gNSkKZ2dzYXZlKHBhc3RlMCgiLi4vT3V0cHV0L1NGUy9ZMTk5Nl9wYWlyd2lzZUZzdC5wbmciKSwgd2lkdGggPSA1LCBoZWlnaHQgPSA1LCBkcGk9MzAwKQoKYGBgCiFbXSguLi9PdXRwdXQvU0ZTL1kxOTk2X3BhaXJ3aXNlRnN0LnBuZykKCgpgYGB7ciBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBldmFsPUZBTFNFfQoKIyAyLiBZMjAwNi8yMDA3CnBvcHM8LWMoIlBXUzA3IiwiU1MwNiIsIlRCMDYiKQpjb21iPC10KGNvbWJuKHBvcHMsMikpCgpmc3Q8LWRhdGEuZnJhbWUoKQpmb3IgKGkgaW4gMTogbnJvdyhjb21iKSl7CiAgICBwb3AxPC1jb21iW2ksMV0KICAgIHBvcDI8LWNvbWJbaSwyXQogICAgZGY8LXJlYWQuZGVsaW0ocGFzdGUwKCIuLi9EYXRhL25ld192Y2YvYW5nc2QvZnJvbVZDRi8yRC9mc3RfZm9sZGVkXyIscG9wMSwiXyIscG9wMiwiXzUwa1dpbmRvd19tYWYwMCIpKQogICAgY29uYW1lczwtY29sbmFtZXMoZGYpWzI6NF0KICAgIGNvbG5hbWVzKGRmKVs0XTwtIkZzdCIKICAgIGNvbG5hbWVzKGRmKVsxOjNdPC1jb25hbWVzCiAgICBkZiRwb3A8LXBhc3RlMChwb3AxLCIudnMuIixwb3AyKQogICAgZGYkY2g9YXMuaW50ZWdlcihnc3ViKCJjaHIiLCIiLCBkZiRjaHIpKQogICAgZGY8LWRmW29yZGVyKGRmJGNoKSxdCiAgICBkZiRsb2M8LTE6bnJvdyhkZikKICAgIGZzdDwtcmJpbmQoZnN0LCBkZikKfQoKI1Bsb3QgRnN0IHZhbHVlcyBhY3Jvc3MgR2Vub21lCmZzdCRjb2xvcjwtImNvbDEiCmZzdCRjb2xvcltmc3QkY2hyICVpbiUgZXZlbnNdPC0iY29sMiIKZnN0JHBvcDwtZmFjdG9yKGZzdCRwb3AsIGxldmVscz11bmlxdWUoZnN0JHBvcCkpCgpnZ3Bsb3QoZnN0LCBhZXMoeD1sb2MsIHk9RnN0LCBjb2xvcj1jb2xvcikpKwogICAgZmFjZXRfd3JhcCh+cG9wLCBuY29sID0gMSwgc3RyaXAucG9zaXRpb249InJpZ2h0IikrCiAgICBnZW9tX3BvaW50KHNpemU9MC4yLCBhbHBoYT0wLjYpKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1jKCJncmF5NjAiLCJzdGVlbGJsdWUiKSkrCiAgICB0aGVtZV9idygpKwogICAgeWxhYigiRnN0IikreGxhYignR2Vub21lIHBvc2l0aW9uJykrCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsIHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSwgcGFuZWwuZ3JpZC5taW5vci54ID0gZWxlbWVudF9ibGFuaygpKStnZ3RpdGxlKCIyMDA2LzA3IikrCiAgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPXJvd3MkbWlkZGxlLCBsYWJlbHM9MToyNikKZ2dzYXZlKCIuLi9PdXRwdXQvU0ZTL1kyMDA2X0ZzdF9wYWlyd2lzZV9jb21wYXJpc29uLnBuZyIsIHdpZHRoID0gMTYsIGhlaWdodCA9IDcsIGRwaT0zMDApCgoKY29tcGFyZTwtdW5pcXVlKGZzdCRwb3ApCnBhaXJmc3Q8LWRhdGEuZnJhbWUobWF0cml4KG5jb2w9MywgbnJvdz0zKSwgcm93Lm5hbWVzPWMoIlRCMDYiLCJQV1MwNyIsIlNTMDYiKSkKY29sbmFtZXMocGFpcmZzdCk8LWMoIlRCMDYiLCJQV1MwNyIsIlNTMDYiKQpmb3IgKGkgaW4gMTozKXsKICAgIHBvcDE8LWNvbWJbaSwxXQogICAgcG9wMjwtY29tYltpLDJdCiAgICBkZjwtZnN0W2ZzdCRwb3A9PWNvbXBhcmVbaV0sXQogICAgcGFpcmZzdFtwb3AxLHBvcDJdPC1tZWFuKGRmJEZzdCwgbmEucm09VCkKICAgIHBhaXJmc3RbcG9wMixwb3AxXTwtbWVhbihkZiRGc3QsIG5hLnJtPVQpCn0Kd3JpdGUuY3N2KHBhaXJmc3QsIi4uL091dHB1dC9TRlMvWTIwMDZfcGFpcndpc2VGc3RfbWF0cml4LmNzdiIpCgpkZjwtcGFpcmZzdApkaWFnKGRmKTwtMApkZltsb3dlci50cmkoZGYpXTwtTkEKZGYkcG9wPC1yb3duYW1lcyhkZikKZGZtPC1tZWx0KGRmLG5hLnJtPVQsIGlkLnZhcnM9J3BvcCcpCiNOQSB0byBkaWFnb25hbApkZm0kdmFsdWVbZGZtJHZhbHVlPT0wXTwtTkEKZGZtJHBvcDwtZmFjdG9yKGRmbSRwb3AsIGxldmVscz1jKCJUQjA2IiwiUFdTMDciLCJTUzA2IikpCmRmbSR2YWx1ZTwtcm91bmQoZGZtJHZhbHVlLCA0KQpnZ3Bsb3QoZGF0YSA9IGRmbSwgYWVzKHBvcCwgdmFyaWFibGUsIGZpbGwgPSB2YWx1ZSkpKwogICAgZ2VvbV90aWxlKGNvbG9yID0gIndoaXRlIikrCiAgICBzY2FsZV9maWxsX2dyYWRpZW50bihjb2xvcnM9Yygid2hpdGUiLCAiIzBDNTRGRkNDIiksIGxpbWl0cz1jKDAsIChtYXgoZGZtJHZhbHVlLCBuYS5ybT1UKSswLjA1KSksbmEudmFsdWU9ImdyYXk4MCIsIAogICAgICAgICAgICAgICAgICAgICAgICAgbmFtZT0iRnN0IikrCiAgICB0aGVtZV9taW5pbWFsKCkrIHhsYWIoIiIpK3lsYWIoIiIpKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSAwLCB2anVzdCA9IDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDEyLCBoanVzdCA9IDAuNSkpKwogICAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDEyKSkrCiAgICBjb29yZF9maXhlZCgpK2dndGl0bGUoIjIwMDYvMDciKSsKICAgIGdlb21fdGV4dChhZXMocG9wLCB2YXJpYWJsZSwgbGFiZWwgPSB2YWx1ZSksIGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDUpCmdnc2F2ZShwYXN0ZTAoIi4uL091dHB1dC9TRlMvWTIwMDZfcGFpcndpc2VGc3QucG5nIiksIHdpZHRoID0gNSwgaGVpZ2h0ID0gNSwgZHBpPTMwMCkKCgojMjAxNwoKCgoKZjE3PC1yZWFkLmNzdigiLi4vT3V0cHV0L1NGUy9Gc3RfbWF0cml4XzIwMTdfYWxsLmNzdiIpCmYxNzwtZjE3WzE6MywxOjRdCiMgTWVsdCB0aGUgY29ycmVsYXRpb24gbWF0cml4CmYxN20gPC0gbWVsdChmMTcsIG5hLnJtID0gVFJVRSkKZjE3bVtmMTdtPT0wXTwtTkEKCmNvbG5hbWVzKGYxN20pWzE6M108LWMoIlAxIiwiUDIiLCJmc3QiKQpmMTdtJFAxPC1mYWN0b3IoZjE3bSRQMSwgbGV2ZWxzPWMoIlRCMTciLCJQV1MxNyIsIlNTMTciKSkKCmdncGxvdChmMTdtLCBhZXMoUDEsIFAyLCBmaWxsID0gZnN0KSkrCiAgICBnZW9tX3RpbGUoY29sb3IgPSAid2hpdGUiKSsKICAgIHNjYWxlX2ZpbGxfZ3JhZGllbnRuKGNvbG9ycz1jKCJ3aGl0ZSIsICIjMEM1NEZGQ0MiKSwgbGltaXRzPWMoMCwgKG1heChmMTdtJGZzdCwgbmEucm09VCkrMC4wNSkpLG5hLnZhbHVlPSJncmF5ODAiLCAgbmFtZT0iRnN0IikrCiAgICAgICAgICAgICAgICAgICAgICAgIAogICAgdGhlbWVfbWluaW1hbCgpKyB4bGFiKCIiKSt5bGFiKCIiKSsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gMCwgdmp1c3QgPSAwLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAxMiwgaGp1c3QgPSAwLjUpKSsKICAgIHRoZW1lKGF4aXMudGV4dC55ID0gZWxlbWVudF90ZXh0KHNpemUgPSAxMikpKwogICAgY29vcmRfZml4ZWQoKSsKICAgIGdlb21fdGV4dChhZXMoUDEsIFAyLCBsYWJlbCA9IGZzdCksICBzaXplID0gNSkKZ2dzYXZlKCIuLi9PdXRwdXQvU0ZTL1kyMDE3X3BhaXJ3aXNlRnN0LnBuZyIsIGhlaWdodCA9IDUsIHdpZHRoID0gNSwgZHBpPTE1MCkKCmBgYAohW10oLi4vT3V0cHV0L1NGUy9ZMjAwNl9wYWlyd2lzZUZzdC5wbmcpCgoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZXZhbD1GQUxTRX0KCiMgMy4gWTE5OTEgCgpkZjwtcmVhZC5kZWxpbShwYXN0ZTAoIi4uL0RhdGEvbmV3X3ZjZi9hbmdzZC9mcm9tVkNGLzJEL2ZzdF9mb2xkZWRfUFdTOTFfVEI5MV81MGtXaW5kb3dfbWFmMDAiKSkKY29uYW1lczwtY29sbmFtZXMoZGYpWzI6NF0KY29sbmFtZXMoZGYpWzRdPC0iRnN0Igpjb2xuYW1lcyhkZilbMTozXTwtY29uYW1lcwpkZiRwb3A8LXBhc3RlMCgiUFdTOTEudnMuVEI5MSIpCmRmJGNoPWFzLmludGVnZXIoZ3N1YigiY2hyIiwiIiwgZGYkY2hyKSkKZGY8LWRmW29yZGVyKGRmJGNoKSxdCmRmJGxvYzwtMTpucm93KGRmKQpmc3Q8LWRmCiNQbG90IEZzdCB2YWx1ZXMgYWNyb3NzIEdlbm9tZQpmc3QkY29sb3I8LSJjb2wxIgpmc3QkY29sb3JbZnN0JGNociAlaW4lIGV2ZW5zXTwtImNvbDIiCmZzdCRwb3A8LWZhY3Rvcihmc3QkcG9wLCBsZXZlbHM9dW5pcXVlKGZzdCRwb3ApKQoKZ2dwbG90KGZzdCwgYWVzKHg9bG9jLCB5PUZzdCwgY29sb3I9Y29sb3IpKSsKICAgIGZhY2V0X3dyYXAofnBvcCwgbmNvbCA9IDEsIHN0cmlwLnBvc2l0aW9uPSJyaWdodCIpKwogICAgZ2VvbV9wb2ludChzaXplPTAuMiwgYWxwaGE9MC42KSsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9YygiZ3JheTYwIiwic3RlZWxibHVlIikpKwogICAgdGhlbWVfYncoKSsKICAgIHlsYWIoIkZzdCIpK3hsYWIoJ0dlbm9tZSBwb3NpdGlvbicpKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLCBwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCksIHBhbmVsLmdyaWQubWlub3IueCA9IGVsZW1lbnRfYmxhbmsoKSkrZ2d0aXRsZSgiMTk5MSIpKwogICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1yb3dzJG1pZGRsZSwgbGFiZWxzPTE6MjYpKwogICAgYW5ub3RhdGUoInRleHQiLCB4PTEsIHk9MC43LCBsYWJlbD0iTWVhbiBGc3QgPSAwLjE0MiIsIGhqdXN0PTApCiAgICAKZ2dzYXZlKCIuLi9PdXRwdXQvU0ZTL1kxOTkxX0ZzdF9wYWlyd2lzZV9jb21wYXJpc29uLnBuZyIsIHdpZHRoID0gMTYsIGhlaWdodCA9IDIuNSwgZHBpPTMwMCkKCnBhaXJmc3Q8LW1lYW4oZnN0JEZzdCwgbmEucm09VCkKCnBhaXJmc3QKIzAuMTQxNzYzNwoKYGBgCiFbXSguLi9PdXRwdXQvU0ZTL1kxOTkxX0ZzdF9wYWlyd2lzZV9jb21wYXJpc29uLnBuZykKCgoK